1
Fork 0

Auto merge of #87375 - fee1-dead:move-constness-to-traitpred, r=oli-obk

Try filtering out non-const impls when we expect const impls

**TL;DR**: Associated types on const impls are now bounded; we now disallow calling a const function with bounds when the specified type param only has a non-const impl.

r? `@oli-obk`
This commit is contained in:
bors 2021-08-14 12:06:34 +00:00
commit 136eaa1b25
68 changed files with 517 additions and 211 deletions

View file

@ -1340,7 +1340,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(pred, _) => {
ty::PredicateKind::Trait(pred) => {
let pred = bound_predicate.rebind(pred);
associated_types.entry(span).or_default().extend(
tcx.associated_items(pred.def_id())

View file

@ -606,16 +606,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut suggest_box = !obligations.is_empty();
for o in obligations {
match o.predicate.kind().skip_binder() {
ty::PredicateKind::Trait(t, constness) => {
let pred = ty::PredicateKind::Trait(
ty::TraitPredicate {
trait_ref: ty::TraitRef {
def_id: t.def_id(),
substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
},
ty::PredicateKind::Trait(t) => {
let pred = ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref: ty::TraitRef {
def_id: t.def_id(),
substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
},
constness,
);
constness: t.constness,
});
let obl = Obligation::new(
o.cause.clone(),
self.param_env,

View file

@ -587,9 +587,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
debug!("coerce_unsized resolve step: {:?}", obligation);
let bound_predicate = obligation.predicate.kind();
let trait_pred = match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(trait_pred, _)
if traits.contains(&trait_pred.def_id()) =>
{
ty::PredicateKind::Trait(trait_pred) if traits.contains(&trait_pred.def_id()) => {
if unsize_did == trait_pred.def_id() {
let self_ty = trait_pred.self_ty();
let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty();

View file

@ -1292,7 +1292,13 @@ pub fn check_type_bounds<'tcx>(
};
tcx.infer_ctxt().enter(move |infcx| {
let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
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 infcx = &inh.infcx;
let mut selcx = traits::SelectionContext::new(&infcx);
@ -1334,7 +1340,9 @@ pub fn check_type_bounds<'tcx>(
// Check that all obligations are satisfied by the implementation's
// version.
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
if let Err(ref errors) =
inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness)
{
infcx.report_fulfillment_errors(errors, None, false);
return Err(ErrorReported);
}

View file

@ -229,7 +229,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
let predicate = predicate.kind();
let p = p.kind();
match (predicate.skip_binder(), p.skip_binder()) {
(ty::PredicateKind::Trait(a, _), ty::PredicateKind::Trait(b, _)) => {
(ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => {
relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
}
(ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {

View file

@ -714,7 +714,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn select_all_obligations_or_error(&self) {
debug!("select_all_obligations_or_error");
if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
if let Err(errors) = self
.fulfillment_cx
.borrow_mut()
.select_all_with_constness_or_error(&self, self.inh.constness)
{
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
}
}
@ -725,7 +729,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fallback_has_occurred: bool,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) {
let result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
let result = self
.fulfillment_cx
.borrow_mut()
.select_with_constness_where_possible(self, self.inh.constness);
if let Err(mut errors) = result {
mutate_fulfillment_errors(&mut errors);
self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
@ -796,7 +803,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
obligation,
)),
ty::PredicateKind::Trait(data, _) => {
ty::PredicateKind::Trait(data) => {
Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
}
ty::PredicateKind::Subtype(..) => None,

View file

@ -923,7 +923,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
continue;
}
if let ty::PredicateKind::Trait(predicate, _) =
if let ty::PredicateKind::Trait(predicate) =
error.obligation.predicate.kind().skip_binder()
{
// Collect the argument position for all arguments that could have caused this
@ -974,7 +974,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let hir::ExprKind::Path(qpath) = &path.kind {
if let hir::QPath::Resolved(_, path) = &qpath {
for error in errors {
if let ty::PredicateKind::Trait(predicate, _) =
if let ty::PredicateKind::Trait(predicate) =
error.obligation.predicate.kind().skip_binder()
{
// If any of the type arguments in this path segment caused the

View file

@ -174,7 +174,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
}
fn default_constness_for_trait_bounds(&self) -> hir::Constness {
self.tcx.hir().get(self.body_id).constness()
self.tcx.hir().get(self.body_id).constness_for_typeck()
}
fn get_type_parameter_bounds(
@ -194,7 +194,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
predicates: tcx.arena.alloc_from_iter(
self.param_env.caller_bounds().iter().filter_map(|predicate| {
match predicate.kind().skip_binder() {
ty::PredicateKind::Trait(data, _) if data.self_ty().is_param(index) => {
ty::PredicateKind::Trait(data) if data.self_ty().is_param(index) => {
// HACK(eddyb) should get the original `Span`.
let span = tcx.def_span(def_id);
Some((predicate, span))

View file

@ -52,6 +52,9 @@ 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>,
}
@ -93,6 +96,16 @@ 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);
@ -108,6 +121,7 @@ impl Inherited<'a, 'tcx> {
deferred_call_resolutions: RefCell::new(Default::default()),
deferred_cast_checks: RefCell::new(Vec::new()),
deferred_generator_interiors: RefCell::new(Vec::new()),
constness,
body_id,
}
}

View file

@ -507,7 +507,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied())
// We don't care about regions here.
.filter_map(|obligation| match obligation.predicate.kind().skip_binder() {
ty::PredicateKind::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => {
ty::PredicateKind::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => {
let span = iter::zip(&predicates.predicates, &predicates.spans)
.find_map(
|(p, span)| {

View file

@ -832,7 +832,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(trait_predicate, _) => {
ty::PredicateKind::Trait(trait_predicate) => {
match *trait_predicate.trait_ref.self_ty().kind() {
ty::Param(p) if p == param_ty => {
Some(bound_predicate.rebind(trait_predicate.trait_ref))

View file

@ -683,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut collect_type_param_suggestions =
|self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| {
// We don't care about regions here, so it's fine to skip the binder here.
if let (ty::Param(_), ty::PredicateKind::Trait(p, _)) =
if let (ty::Param(_), ty::PredicateKind::Trait(p)) =
(self_ty.kind(), parent_pred.kind().skip_binder())
{
if let ty::Adt(def, _) = p.trait_ref.self_ty().kind() {
@ -763,7 +763,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty()))
}
ty::PredicateKind::Trait(poly_trait_ref, _) => {
ty::PredicateKind::Trait(poly_trait_ref) => {
let p = poly_trait_ref.trait_ref;
let self_ty = p.self_ty();
let path = p.print_only_trait_path();
@ -1200,7 +1200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match p.kind().skip_binder() {
// Hide traits if they are present in predicates as they can be fixed without
// having to implement them.
ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id,
ty::PredicateKind::Trait(t) => t.def_id() == info.def_id,
ty::PredicateKind::Projection(p) => {
p.projection_ty.item_def_id == info.def_id
}

View file

@ -689,7 +689,7 @@ fn bounds_from_generic_predicates<'tcx>(
debug!("predicate {:?}", predicate);
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(trait_predicate, _) => {
ty::PredicateKind::Trait(trait_predicate) => {
let entry = types.entry(trait_predicate.self_ty()).or_default();
let def_id = trait_predicate.def_id();
if Some(def_id) != tcx.lang_items().sized_trait() {

View file

@ -364,7 +364,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
}
fn default_constness_for_trait_bounds(&self) -> hir::Constness {
self.node().constness()
self.node().constness_for_typeck()
}
fn get_type_parameter_bounds(
@ -640,7 +640,7 @@ fn type_param_predicates(
)
.into_iter()
.filter(|(predicate, _)| match predicate.kind().skip_binder() {
ty::PredicateKind::Trait(data, _) => data.self_ty().is_param(index),
ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
_ => false,
}),
);
@ -1198,7 +1198,7 @@ fn super_predicates_that_define_assoc_type(
// which will, in turn, reach indirect supertraits.
for &(pred, span) in superbounds {
debug!("superbound: {:?}", pred);
if let ty::PredicateKind::Trait(bound, _) = pred.kind().skip_binder() {
if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
tcx.at(span).super_predicates_of(bound.def_id());
}
}
@ -2439,7 +2439,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
.iter()
.copied()
.filter(|(pred, _)| match pred.kind().skip_binder() {
ty::PredicateKind::Trait(tr, _) => !is_assoc_item_ty(tr.self_ty()),
ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
ty::PredicateKind::Projection(proj) => {
!is_assoc_item_ty(proj.projection_ty.self_ty())
}

View file

@ -38,7 +38,7 @@ fn associated_type_bounds<'tcx>(
let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
match pred.kind().skip_binder() {
ty::PredicateKind::Trait(tr, _) => tr.self_ty() == item_ty,
ty::PredicateKind::Trait(tr) => tr.self_ty() == item_ty,
ty::PredicateKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
ty::PredicateKind::TypeOutlives(outlives) => outlives.0 == item_ty,
_ => false,

View file

@ -366,7 +366,10 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
_ if predicate.is_global() => (),
// We allow specializing on explicitly marked traits with no associated
// items.
ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => {
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: hir::Constness::NotConst,
}) => {
if !matches!(
trait_predicate_kind(tcx, predicate),
Some(TraitSpecializationKind::Marker)
@ -376,7 +379,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
span,
&format!(
"cannot specialize on trait `{}`",
tcx.def_path_str(pred.def_id()),
tcx.def_path_str(trait_ref.def_id),
),
)
.emit()
@ -394,10 +397,11 @@ fn trait_predicate_kind<'tcx>(
predicate: ty::Predicate<'tcx>,
) -> Option<TraitSpecializationKind> {
match predicate.kind().skip_binder() {
ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => {
Some(tcx.trait_def(pred.def_id()).specialization_kind)
}
ty::PredicateKind::Trait(_, hir::Constness::Const)
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: hir::Constness::NotConst,
}) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
ty::PredicateKind::Trait(_)
| ty::PredicateKind::RegionOutlives(_)
| ty::PredicateKind::TypeOutlives(_)
| ty::PredicateKind::Projection(_)