Skip to content

Commit

Permalink
pass ast_index to LoweringContext and lower impls correctly
Browse files Browse the repository at this point in the history
plus some other fixes.
  • Loading branch information
fee1-dead committed Feb 9, 2024
1 parent e80f33b commit 0781e50
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 15 deletions.
25 changes: 20 additions & 5 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
owner: NodeId,
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
) {
let mut lctx = LoweringContext::new(self.tcx, self.resolver);
let mut lctx = LoweringContext::new(self.tcx, self.resolver, self.ast_index);
lctx.with_hir_id_owner(owner, |lctx| f(lctx));

for (def_id, info) in lctx.children {
Expand Down Expand Up @@ -579,10 +579,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
let constness = match parent_item.kind {
hir::ItemKind::Impl(impl_) => {
self.is_in_trait_impl = impl_.of_trait.is_some();
match impl_.constness {
// TODO bad span
hir::Constness::Const => Const::Yes(impl_.self_ty.span),
hir::Constness::NotConst => Const::No,
// N.B. the impl should always lower to methods that have `const host: bool` params if the trait
// is const. It doesn't matter whether the `impl` itself is const. Disallowing const fn from
// calling non-const impls are done through associated types.
if let Some(def_id) = impl_.of_trait.and_then(|tr| tr.trait_def_id()) {
if let Some(local_def) = def_id.as_local() {
match &self.ast_index[local_def] {
AstOwner::Item(ast::Item { attrs, .. }) => attrs
.iter()
.find(|attr| attr.has_name(sym::const_trait))
.map_or(Const::No, |attr| Const::Yes(attr.span)),
_ => Const::No,
}
} else {
self.tcx
.get_attr(def_id, sym::const_trait)
.map_or(Const::No, |attr| Const::Yes(attr.span))
}
} else {
Const::No
}
}
hir::ItemKind::Trait(_, _, _, _, _) => parent_hir
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,19 @@ struct LoweringContext<'a, 'hir> {
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) -> Self {
fn new(
tcx: TyCtxt<'hir>,
resolver: &'a mut ResolverAstLowering,
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
) -> Self {
Self {
// Pseudo-globals.
tcx,
resolver: resolver,
resolver,
arena: tcx.hir_arena,

// HirId handling.
Expand Down Expand Up @@ -181,6 +186,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
generics_def_id_map: Default::default(),
host_param_id: None,
ast_index,
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ language_item_table! {
EffectsNoRuntime, sym::EffectsNoRuntime, effects_no_runtime, Target::Struct, GenericRequirement::None;
EffectsMaybe, sym::EffectsMaybe, effects_maybe, Target::Struct, GenericRequirement::None;
EffectsCompat, sym::EffectsCompat, effects_compat, Target::Trait, GenericRequirement::Exact(1);
EffectsEq, sym::EffectsEq, effects_eq, Target::Trait, GenericRequirement::Exact(1);
}

pub enum GenericRequirement {
Expand Down
53 changes: 46 additions & 7 deletions compiler/rustc_hir_analysis/src/bounds.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Bounds are restrictions applied to some types after they've been converted into the
//! `ty` form from the HIR.
use rustc_hir::LangItem;
use rustc_hir::{def::DefKind, LangItem};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_span::{def_id::DefId, Span};

Expand Down Expand Up @@ -54,15 +54,54 @@ impl<'tcx> Bounds<'tcx> {
.to_predicate(tcx),
span,
));
// 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.
if let Some(compat_val) = match constness {
if let Some(compat_val) = match (tcx.def_kind(defining_def_id), constness) {
// TODO: do we need `T: const Trait` anymore?
ty::BoundConstness::Const => Some(tcx.consts.false_),
ty::BoundConstness::ConstIfConst => {
(_, ty::BoundConstness::Const) => Some(tcx.consts.false_),
// body owners that can have trait bounds
(DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => {
Some(tcx.expected_host_effect_param_for_body(defining_def_id))
}
ty::BoundConstness::NotConst => None,

(_, ty::BoundConstness::NotConst) => None,

// if the defining_def_id is a trait, we wire it differently than others by equating the effects.
(
kind @ (DefKind::Trait | DefKind::Impl { of_trait: true }),
ty::BoundConstness::ConstIfConst,
) => {
let trait_we_are_in = if let DefKind::Trait = kind {
ty::TraitRef::identity(tcx, defining_def_id)
} else {
tcx.impl_trait_ref(defining_def_id).unwrap().instantiate_identity()
};
// create a new projection type `<T as TraitForBound>::Effects`
let assoc = tcx.associated_type_for_effects(trait_ref.def_id()).unwrap();
let self_ty = Ty::new_projection(tcx, assoc, trait_ref.skip_binder().args);
// we might have `~const Tr` where `Tr` isn't a `#[const_trait]`.
let Some(assoc_def) = tcx.associated_type_for_effects(trait_we_are_in.def_id)
else {
tcx.dcx().span_delayed_bug(
span,
"`~const` bound trait has no effect param yet no errors encountered?",
);
return;
};
let fx_ty_trait_we_are_in =
Ty::new_projection(tcx, assoc_def, trait_we_are_in.args);
// make `<T as TraitForBound>::Effects: EffectsEq<<Self as TraitWeAreIn>::Effects>`
let new_trait_ref = ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::EffectsEq, Some(span)),
[self_ty, fx_ty_trait_we_are_in],
);
self.clauses.push((trait_ref.rebind(new_trait_ref).to_predicate(tcx), span));
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 assoc = tcx.associated_type_for_effects(trait_ref.def_id()).unwrap();
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,7 @@ fn impl_trait_ref(
tcx.is_const_trait_impl_raw(def_id.to_def_id()),
ast_trait_ref,
) {
// TODO this is wrong
// we have a const impl, but for a trait without `#[const_trait]`, so
// without the host param. If we continue with the HIR trait ref, we get
// ICEs for generic arg count mismatch. We do a little HIR editing to
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ symbols! {
DoubleEndedIterator,
Duration,
EffectsCompat,
EffectsEq,
EffectsMaybe,
EffectsNoRuntime,
EffectsRuntime,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5112,6 +5112,12 @@ fn point_at_assoc_type_restriction(
let ty::ClauseKind::Projection(proj) = clause else {
return;
};
// avoid ICEing since effects desugared associated types don't have names.
// this path should only be hit for `~const` on invalid places, so they
// will have an informative error already.
if tcx.is_effects_desugared_assoc_ty(proj.projection_ty.def_id) {
return;
}
let name = tcx.item_name(proj.projection_ty.def_id);
let mut predicates = generics.predicates.iter().peekable();
let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None;
Expand Down
7 changes: 7 additions & 0 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,7 @@ pub trait FnPtr: Copy + Clone {
)]
#[allow(missing_debug_implementations)] // these unit structs don't need `Debug` impls.
#[cfg(not(bootstrap))]
// TODO docs
pub mod effects {
#[lang = "EffectsNoRuntime"]
pub struct NoRuntime;
Expand All @@ -1118,4 +1119,10 @@ pub mod effects {
impl Compat<false> for NoRuntime {}
impl Compat<true> for Runtime {}
impl<const RUNTIME: bool> Compat<RUNTIME> for Maybe {}

#[lang = "EffectsEq"]
pub trait EffectsEq<T: ?Sized> {}
impl EffectsEq<NoRuntime> for NoRuntime {}
impl EffectsEq<Maybe> for Maybe {}
impl EffectsEq<Runtime> for Runtime {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,21 @@ help: wrap the field type in `ManuallyDrop<...>`
LL | union Union<T: ~const Trait> { field: std::mem::ManuallyDrop<T> }
| +++++++++++++++++++++++ +

error[E0275]: overflow evaluating the requirement `(): Trait`
error[E0275]: overflow evaluating the requirement `Trait::{opaque#0} == _`
--> $DIR/tilde-const-invalid-places.rs:34:34
|
LL | type Type<T: ~const Trait> = ();
| ^^
|
note: required for `()` to implement `Trait`
--> $DIR/tilde-const-invalid-places.rs:56:23
|
LL | impl<T: ~const Trait> Trait for T {}
| ------------ ^^^^^ ^
| |
| unsatisfied trait bound introduced here
= note: 1 redundant requirement hidden
= note: required for `()` to implement `Trait`
note: required by a bound in `NonConstTrait::Type`
--> $DIR/tilde-const-invalid-places.rs:25:33
|
Expand Down

0 comments on commit 0781e50

Please sign in to comment.