Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Represent trait constness as a distinct predicate #131985

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 19 additions & 186 deletions compiler/rustc_ast_lowering/src/item.rs

Large diffs are not rendered by default.

20 changes: 3 additions & 17 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,10 @@ struct LoweringContext<'a, 'hir> {
/// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
/// field from the original parameter 'a to the new parameter 'a1.
generics_def_id_map: Vec<LocalDefIdMap<LocalDefId>>,

host_param_id: Option<LocalDefId>,
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
}

impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn new(
tcx: TyCtxt<'hir>,
resolver: &'a mut ResolverAstLowering,
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
) -> Self {
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self {
Self {
// Pseudo-globals.
tcx,
Expand Down Expand Up @@ -204,8 +197,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// interact with `gen`/`async gen` blocks
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
generics_def_id_map: Default::default(),
host_param_id: None,
ast_index,
}
}

Expand Down Expand Up @@ -2054,11 +2045,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param: &GenericParam,
source: hir::GenericParamSource,
) -> hir::GenericParam<'hir> {
let (name, kind) = self.lower_generic_param_kind(
param,
source,
attr::contains_name(&param.attrs, sym::rustc_runtime),
);
let (name, kind) = self.lower_generic_param_kind(param, source);

let hir_id = self.lower_node_id(param.id);
self.lower_attrs(hir_id, &param.attrs);
Expand All @@ -2078,7 +2065,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
param: &GenericParam,
source: hir::GenericParamSource,
is_host_effect: bool,
) -> (hir::ParamName, hir::GenericParamKind<'hir>) {
match &param.kind {
GenericParamKind::Lifetime => {
Expand Down Expand Up @@ -2144,7 +2130,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {

(
hir::ParamName::Plain(self.lower_ident(param.ident)),
hir::GenericParamKind::Const { ty, default, is_host_effect, synthetic: false },
hir::GenericParamKind::Const { ty, default, synthetic: false },
)
}
}
Expand Down
52 changes: 3 additions & 49 deletions compiler/rustc_const_eval/src/check_consts/qualifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*;
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
use rustc_middle::{bug, mir};
use rustc_trait_selection::traits::{
ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
};
use tracing::{instrument, trace};
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
use tracing::instrument;

use super::ConstCx;

Expand Down Expand Up @@ -195,50 +192,7 @@ impl Qualif for NeedsNonConstDrop {
return false;
}

// FIXME(effects): If `destruct` is not a `const_trait`,
// or effects are disabled in this crate, then give up.
let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span));
if !cx.tcx.has_host_param(destruct_def_id) || !cx.tcx.features().effects {
return NeedsDrop::in_any_value_of_ty(cx, ty);
}

let obligation = Obligation::new(
cx.tcx,
ObligationCause::dummy_with_span(cx.body.span),
cx.param_env,
ty::TraitRef::new(cx.tcx, destruct_def_id, [
ty::GenericArg::from(ty),
ty::GenericArg::from(cx.tcx.expected_host_effect_param_for_body(cx.def_id())),
]),
);

let infcx = cx.tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
// If we couldn't select a const destruct candidate, then it's bad
return true;
};

trace!(?impl_src);

if !matches!(
impl_src,
ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(_)
) {
// If our const destruct candidate is not ConstDestruct or implied by the param env,
// then it's bad
return true;
}

if impl_src.borrow_nested_obligations().is_empty() {
return false;
}

// If we had any errors, then it's bad
let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligations(impl_src.nested_obligations());
let errors = ocx.select_all_or_error();
!errors.is_empty()
NeedsDrop::in_any_value_of_ty(cx, ty)
}

fn in_adt_inherently<'tcx>(
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -840,10 +840,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_const_panic_str, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
),
rustc_attr!(
rustc_runtime, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, INTERNAL_UNSTABLE
),

// ==========================================================================
// Internal attributes, Layout related:
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,6 @@ pub enum GenericParamKind<'hir> {
ty: &'hir Ty<'hir>,
/// Optional default value for the const generic param
default: Option<&'hir ConstArg<'hir>>,
is_host_effect: bool,
synthetic: bool,
},
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -935,7 +935,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
match param.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { ref default, .. } => visit_opt!(visitor, visit_ty, default),
GenericParamKind::Const { ref ty, ref default, is_host_effect: _, synthetic: _ } => {
GenericParamKind::Const { ref ty, ref default, synthetic: _ } => {
try_visit!(visitor.visit_ty(ty));
if let Some(ref default) = default {
try_visit!(visitor.visit_const_param_default(param.hir_id, default));
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,14 +415,6 @@ language_item_table! {

String, sym::String, string, Target::Struct, GenericRequirement::None;
CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None;

EffectsRuntime, sym::EffectsRuntime, effects_runtime, Target::Struct, GenericRequirement::None;
EffectsNoRuntime, sym::EffectsNoRuntime, effects_no_runtime, Target::Struct, GenericRequirement::None;
EffectsMaybe, sym::EffectsMaybe, effects_maybe, Target::Struct, GenericRequirement::None;
EffectsIntersection, sym::EffectsIntersection, effects_intersection, Target::Trait, GenericRequirement::None;
EffectsIntersectionOutput, sym::EffectsIntersectionOutput, effects_intersection_output, Target::AssocTy, GenericRequirement::None;
EffectsCompat, sym::EffectsCompat, effects_compat, Target::Trait, GenericRequirement::Exact(1);
EffectsTyCompat, sym::EffectsTyCompat, effects_ty_compat, Target::Trait, GenericRequirement::Exact(1);
}

pub enum GenericRequirement {
Expand Down
149 changes: 11 additions & 138 deletions compiler/rustc_hir_analysis/src/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@

use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::LangItem;
use rustc_hir::def::DefKind;
use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
use rustc_span::Span;
use rustc_span::def_id::DefId;

use crate::hir_ty_lowering::PredicateFilter;

/// Collects together a list of type bounds. These lists of bounds occur in many places
/// in Rust's syntax:
Expand Down Expand Up @@ -47,12 +42,9 @@ impl<'tcx> Bounds<'tcx> {
pub(crate) fn push_trait_bound(
&mut self,
tcx: TyCtxt<'tcx>,
defining_def_id: DefId,
bound_trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
polarity: ty::PredicatePolarity,
constness: ty::BoundConstness,
predicate_filter: PredicateFilter,
) {
let clause = (
bound_trait_ref
Expand All @@ -68,136 +60,6 @@ impl<'tcx> Bounds<'tcx> {
} else {
self.clauses.push(clause);
}

// FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else.
// Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated
// type bounds.
if !tcx.features().effects {
return;
}
match predicate_filter {
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
return;
}
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
// Ok.
}
}

// For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the
// associated type of `<T as Tr>` and make sure that the effect is compatible.
let compat_val = match (tcx.def_kind(defining_def_id), constness) {
// FIXME(effects): revisit the correctness of this
(_, ty::BoundConstness::Const) => tcx.consts.false_,
// body owners that can have trait bounds
(DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => {
tcx.expected_host_effect_param_for_body(defining_def_id)
}

(_, ty::BoundConstness::NotConst) => {
if !tcx.is_const_trait(bound_trait_ref.def_id()) {
return;
}
tcx.consts.true_
}
(DefKind::Trait, ty::BoundConstness::ConstIfConst) => {
// we are in a trait, where `bound_trait_ref` could be:
// (1) a super trait `trait Foo: ~const Bar`.
// - This generates `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>`
//
// (2) a where clause `where for<..> Something: ~const Bar`.
// - This generates `for<..> <Self as Foo>::Effects: TyCompat<<Something as Bar>::Effects>`
let Some(own_fx) = tcx.associated_type_for_effects(defining_def_id) else {
tcx.dcx().span_delayed_bug(span, "should not have allowed `~const` on a trait that doesn't have `#[const_trait]`");
return;
};
let own_fx_ty = Ty::new_projection(
tcx,
own_fx,
ty::GenericArgs::identity_for_item(tcx, own_fx),
);
let Some(their_fx) = tcx.associated_type_for_effects(bound_trait_ref.def_id())
else {
tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
return;
};
let their_fx_ty =
Ty::new_projection(tcx, their_fx, bound_trait_ref.skip_binder().args);
let compat = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span));
let clause = bound_trait_ref
.map_bound(|_| {
let trait_ref = ty::TraitRef::new(tcx, compat, [own_fx_ty, their_fx_ty]);
ty::ClauseKind::Trait(ty::TraitPredicate {
trait_ref,
polarity: ty::PredicatePolarity::Positive,
})
})
.upcast(tcx);

self.clauses.push((clause, span));
return;
}

(DefKind::Impl { of_trait: true }, ty::BoundConstness::ConstIfConst) => {
// this is a where clause on an impl header.
// push `<T as Tr>::Effects` into the set for the `Min` bound.
let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
return;
};

let ty = bound_trait_ref
.map_bound(|trait_ref| Ty::new_projection(tcx, assoc, trait_ref.args));

// When the user has written `for<'a, T> X<'a, T>: ~const Foo`, replace the
// binders to dummy ones i.e. `X<'static, ()>` so they can be referenced in
// the `Min` associated type properly (which doesn't allow using `for<>`)
// This should work for any bound variables as long as they don't have any
// bounds e.g. `for<T: Trait>`.
// FIXME(effects) reconsider this approach to allow compatibility with `for<T: Tr>`
let ty = tcx.replace_bound_vars_uncached(ty, FnMutDelegate {
regions: &mut |_| tcx.lifetimes.re_static,
types: &mut |_| tcx.types.unit,
consts: &mut |_| unimplemented!("`~const` does not support const binders"),
});

self.effects_min_tys.insert(ty, span);
return;
}
// for
// ```
// trait Foo { type Bar: ~const Trait }
// ```
// ensure that `<Self::Bar as Trait>::Effects: TyCompat<Self::Effects>`.
//
// FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor
// that uses a `Bar` that implements `Trait` with `Maybe` effects.
(DefKind::AssocTy, ty::BoundConstness::ConstIfConst) => {
// FIXME(effects): implement this
return;
}
// probably illegal in this position.
(_, ty::BoundConstness::ConstIfConst) => {
tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered");
return;
}
};
// create a new projection type `<T as Tr>::Effects`
let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
tcx.dcx().span_delayed_bug(
span,
"`~const` trait bound has no effect assoc yet no errors encountered?",
);
return;
};
let self_ty = Ty::new_projection(tcx, assoc, bound_trait_ref.skip_binder().args);
// make `<T as Tr>::Effects: Compat<runtime>`
let new_trait_ref =
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::EffectsCompat, Some(span)), [
ty::GenericArg::from(self_ty),
compat_val.into(),
]);
self.clauses.push((bound_trait_ref.rebind(new_trait_ref).upcast(tcx), span));
}

pub(crate) fn push_projection_bound(
Expand All @@ -219,6 +81,17 @@ impl<'tcx> Bounds<'tcx> {
self.clauses.insert(0, (trait_ref.upcast(tcx), span));
}

/// Push a `const` or `~const` bound as a `HostEffect` predicate.
pub(crate) fn push_const_bound(
&mut self,
tcx: TyCtxt<'tcx>,
bound_trait_ref: ty::PolyTraitRef<'tcx>,
host: ty::HostPolarity,
span: Span,
) {
self.clauses.push((bound_trait_ref.to_host_effect(tcx, host), span));
}

pub(crate) fn clauses(
&self,
// FIXME(effects): remove tcx
Expand Down
Loading
Loading