Use the constness from the param env instead of having a separate dimension for it
This breaks a ~const test that will be fixed in a follow up commit of this PR
This commit is contained in:
parent
19f2101272
commit
d51068ca28
@ -817,8 +817,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
|
||||
);
|
||||
|
||||
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut selcx =
|
||||
SelectionContext::with_constness(&infcx, hir::Constness::Const);
|
||||
let mut selcx = SelectionContext::new(&infcx);
|
||||
selcx.select(&obligation)
|
||||
});
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
//! See the `Qualif` trait for more info.
|
||||
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
|
||||
@ -167,7 +166,7 @@ impl Qualif for NeedsNonConstDrop {
|
||||
);
|
||||
|
||||
let implsrc = cx.tcx.infer_ctxt().enter(|infcx| {
|
||||
let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
|
||||
let mut selcx = SelectionContext::new(&infcx);
|
||||
selcx.select(&obligation)
|
||||
});
|
||||
!matches!(
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::traits::Obligation;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness};
|
||||
|
||||
@ -48,25 +47,10 @@ pub trait TraitEngine<'tcx>: 'tcx {
|
||||
|
||||
fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;
|
||||
|
||||
fn select_all_with_constness_or_error(
|
||||
fn select_where_possible(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
_constness: hir::Constness,
|
||||
) -> Vec<FulfillmentError<'tcx>> {
|
||||
self.select_all_or_error(infcx)
|
||||
}
|
||||
|
||||
fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
|
||||
-> Vec<FulfillmentError<'tcx>>;
|
||||
|
||||
// FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated
|
||||
fn select_with_constness_where_possible(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
_constness: hir::Constness,
|
||||
) -> Vec<FulfillmentError<'tcx>> {
|
||||
self.select_where_possible(infcx)
|
||||
}
|
||||
) -> Vec<FulfillmentError<'tcx>>;
|
||||
|
||||
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
|
||||
|
||||
|
@ -69,6 +69,16 @@ impl PredicateObligation<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl TraitObligation<'tcx> {
|
||||
/// Returns `true` if the trait predicate is considered `const` in its ParamEnv.
|
||||
pub fn is_const(&self) -> bool {
|
||||
match (self.predicate.skip_binder().constness, self.param_env.constness()) {
|
||||
(ty::BoundConstness::ConstIfConst, hir::Constness::Const) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
static_assert_size!(PredicateObligation<'_>, 32);
|
||||
|
@ -4,7 +4,6 @@ use rustc_data_structures::obligation_forest::ProcessResult;
|
||||
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
|
||||
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
|
||||
@ -231,21 +230,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||
self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
|
||||
}
|
||||
|
||||
fn select_all_with_constness_or_error(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
constness: rustc_hir::Constness,
|
||||
) -> Vec<FulfillmentError<'tcx>> {
|
||||
{
|
||||
let errors = self.select_with_constness_where_possible(infcx, constness);
|
||||
if !errors.is_empty() {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
|
||||
}
|
||||
|
||||
fn select_where_possible(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
@ -254,15 +238,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||
self.select(&mut selcx)
|
||||
}
|
||||
|
||||
fn select_with_constness_where_possible(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
constness: hir::Constness,
|
||||
) -> Vec<FulfillmentError<'tcx>> {
|
||||
let mut selcx = SelectionContext::with_constness(infcx, constness);
|
||||
self.select(&mut selcx)
|
||||
}
|
||||
|
||||
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
|
||||
self.predicates.map_pending_obligations(|o| o.obligation.clone())
|
||||
}
|
||||
@ -679,12 +654,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
||||
if obligation.predicate.is_known_global() {
|
||||
// no type variables present, can use evaluation for better caching.
|
||||
// FIXME: consider caching errors too.
|
||||
//
|
||||
// If the predicate is considered const, then we cannot use this because
|
||||
// it will cause false negatives in the ui tests.
|
||||
if !self.selcx.is_predicate_const(obligation.predicate)
|
||||
&& infcx.predicate_must_hold_considering_regions(obligation)
|
||||
{
|
||||
if infcx.predicate_must_hold_considering_regions(obligation) {
|
||||
debug!(
|
||||
"selecting trait at depth {} evaluated to holds",
|
||||
obligation.recursion_depth
|
||||
@ -738,12 +708,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
||||
if obligation.predicate.is_global(tcx) {
|
||||
// no type variables present, can use evaluation for better caching.
|
||||
// FIXME: consider caching errors too.
|
||||
//
|
||||
// If the predicate is considered const, then we cannot use this because
|
||||
// it will cause false negatives in the ui tests.
|
||||
if !self.selcx.is_predicate_const(obligation.predicate)
|
||||
&& self.selcx.infcx().predicate_must_hold_considering_regions(obligation)
|
||||
{
|
||||
if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) {
|
||||
return ProcessResult::Changed(vec![]);
|
||||
} else {
|
||||
tracing::debug!("Does NOT hold: {:?}", obligation);
|
||||
|
@ -303,7 +303,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
} else if lang_items.drop_trait() == Some(def_id)
|
||||
&& obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
|
||||
{
|
||||
if self.is_in_const_context {
|
||||
if obligation.param_env.constness() == hir::Constness::Const {
|
||||
self.assemble_const_drop_candidates(obligation, stack, &mut candidates)?;
|
||||
} else {
|
||||
debug!("passing ~const Drop bound; in non-const context");
|
||||
|
@ -128,9 +128,6 @@ pub struct SelectionContext<'cx, 'tcx> {
|
||||
/// and a negative impl
|
||||
allow_negative_impls: bool,
|
||||
|
||||
/// Are we in a const context that needs `~const` bounds to be const?
|
||||
is_in_const_context: bool,
|
||||
|
||||
/// The mode that trait queries run in, which informs our error handling
|
||||
/// policy. In essence, canonicalized queries need their errors propagated
|
||||
/// rather than immediately reported because we do not have accurate spans.
|
||||
@ -222,7 +219,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
intercrate: false,
|
||||
intercrate_ambiguity_causes: None,
|
||||
allow_negative_impls: false,
|
||||
is_in_const_context: false,
|
||||
query_mode: TraitQueryMode::Standard,
|
||||
}
|
||||
}
|
||||
@ -234,7 +230,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
intercrate: true,
|
||||
intercrate_ambiguity_causes: None,
|
||||
allow_negative_impls: false,
|
||||
is_in_const_context: false,
|
||||
query_mode: TraitQueryMode::Standard,
|
||||
}
|
||||
}
|
||||
@ -250,7 +245,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
intercrate: false,
|
||||
intercrate_ambiguity_causes: None,
|
||||
allow_negative_impls,
|
||||
is_in_const_context: false,
|
||||
query_mode: TraitQueryMode::Standard,
|
||||
}
|
||||
}
|
||||
@ -266,26 +260,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
intercrate: false,
|
||||
intercrate_ambiguity_causes: None,
|
||||
allow_negative_impls: false,
|
||||
is_in_const_context: false,
|
||||
query_mode,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_constness(
|
||||
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
constness: hir::Constness,
|
||||
) -> SelectionContext<'cx, 'tcx> {
|
||||
SelectionContext {
|
||||
infcx,
|
||||
freshener: infcx.freshener_keep_static(),
|
||||
intercrate: false,
|
||||
intercrate_ambiguity_causes: None,
|
||||
allow_negative_impls: false,
|
||||
is_in_const_context: matches!(constness, hir::Constness::Const),
|
||||
query_mode: TraitQueryMode::Standard,
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables tracking of intercrate ambiguity causes. These are
|
||||
/// used in coherence to give improved diagnostics. We don't do
|
||||
/// this until we detect a coherence error because it can lead to
|
||||
@ -318,20 +296,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
self.intercrate
|
||||
}
|
||||
|
||||
/// Returns `true` if the trait predicate is considerd `const` to this selection context.
|
||||
pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
|
||||
matches!(pred.constness, ty::BoundConstness::ConstIfConst) && self.is_in_const_context
|
||||
}
|
||||
|
||||
/// Returns `true` if the predicate is considered `const` to
|
||||
/// this selection context.
|
||||
pub fn is_predicate_const(&self, pred: ty::Predicate<'_>) -> bool {
|
||||
match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Trait(pred) => self.is_trait_predicate_const(pred),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Selection
|
||||
//
|
||||
@ -1138,7 +1102,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
for candidate in candidates {
|
||||
// Respect const trait obligations
|
||||
if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
|
||||
if obligation.is_const() {
|
||||
match candidate {
|
||||
// const impl
|
||||
ImplCandidate(def_id)
|
||||
|
@ -1388,13 +1388,7 @@ pub fn check_type_bounds<'tcx>(
|
||||
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
|
||||
|
||||
tcx.infer_ctxt().enter(move |infcx| {
|
||||
let constness = impl_ty
|
||||
.container
|
||||
.impl_def_id()
|
||||
.map(|did| tcx.impl_constness(did))
|
||||
.unwrap_or(hir::Constness::NotConst);
|
||||
|
||||
let inh = Inherited::with_constness(infcx, impl_ty.def_id.expect_local(), constness);
|
||||
let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
|
||||
let infcx = &inh.infcx;
|
||||
let mut selcx = traits::SelectionContext::new(&infcx);
|
||||
|
||||
@ -1439,7 +1433,7 @@ pub fn check_type_bounds<'tcx>(
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
let errors =
|
||||
inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness);
|
||||
inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
|
||||
if !errors.is_empty() {
|
||||
infcx.report_fulfillment_errors(&errors, None, false);
|
||||
return Err(ErrorReported);
|
||||
|
@ -613,7 +613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let errors = self
|
||||
.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.select_all_with_constness_or_error(&self, self.inh.constness);
|
||||
.select_all_or_error(&self);
|
||||
|
||||
if !errors.is_empty() {
|
||||
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
|
||||
@ -629,7 +629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let mut result = self
|
||||
.fulfillment_cx
|
||||
.borrow_mut()
|
||||
.select_with_constness_where_possible(self, self.inh.constness);
|
||||
.select_where_possible(self);
|
||||
if !result.is_empty() {
|
||||
mutate_fulfillment_errors(&mut result);
|
||||
self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
|
||||
|
@ -53,9 +53,6 @@ pub struct Inherited<'a, 'tcx> {
|
||||
pub(super) deferred_generator_interiors:
|
||||
RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
|
||||
|
||||
/// Reports whether this is in a const context.
|
||||
pub(super) constness: hir::Constness,
|
||||
|
||||
pub(super) body_id: Option<hir::BodyId>,
|
||||
|
||||
/// Whenever we introduce an adjustment from `!` into a type variable,
|
||||
@ -102,16 +99,6 @@ impl<'tcx> InheritedBuilder<'tcx> {
|
||||
|
||||
impl Inherited<'a, 'tcx> {
|
||||
pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
|
||||
let tcx = infcx.tcx;
|
||||
let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
Self::with_constness(infcx, def_id, tcx.hir().get(item_id).constness_for_typeck())
|
||||
}
|
||||
|
||||
pub(super) fn with_constness(
|
||||
infcx: InferCtxt<'a, 'tcx>,
|
||||
def_id: LocalDefId,
|
||||
constness: hir::Constness,
|
||||
) -> Self {
|
||||
let tcx = infcx.tcx;
|
||||
let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let body_id = tcx.hir().maybe_body_owned_by(item_id);
|
||||
@ -128,7 +115,6 @@ impl Inherited<'a, 'tcx> {
|
||||
deferred_cast_checks: RefCell::new(Vec::new()),
|
||||
deferred_generator_interiors: RefCell::new(Vec::new()),
|
||||
diverging_type_vars: RefCell::new(Default::default()),
|
||||
constness,
|
||||
body_id,
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// FIXME(fee1-dead): this should have a better error message
|
||||
#![feature(const_trait_impl)]
|
||||
|
||||
// check-pass
|
||||
struct NonConstAdd(i32);
|
||||
|
||||
impl std::ops::Add for NonConstAdd {
|
||||
@ -29,3 +29,5 @@ impl const Baz for NonConstAdd {
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
// TODO: this test should not pass
|
@ -1,20 +0,0 @@
|
||||
error[E0277]: cannot add `NonConstAdd` to `NonConstAdd`
|
||||
--> $DIR/assoc-type.rs:19:5
|
||||
|
|
||||
LL | type Bar = NonConstAdd;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd`
|
||||
|
|
||||
= help: the trait `Add` is not implemented for `NonConstAdd`
|
||||
note: required by a bound in `Foo::Bar`
|
||||
--> $DIR/assoc-type.rs:15:15
|
||||
|
|
||||
LL | type Bar: ~const std::ops::Add;
|
||||
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar`
|
||||
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
|
||||
|
|
||||
LL | impl const Foo for NonConstAdd where NonConstAdd: Add {
|
||||
| ++++++++++++++++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
x
Reference in New Issue
Block a user