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

generic const items: support effects #117530

Closed
Closed
Show file tree
Hide file tree
Changes from all 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
81 changes: 56 additions & 25 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
use super::ResolverAstLoweringExt;
use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
use super::{FnDeclKind, LoweringContext, ParamMode};
use super::{EffectContext, FnDeclKind, LoweringContext, ParamMode};

use hir::definitions::DefPathData;
use rustc_ast::ptr::P;
Expand Down Expand Up @@ -90,7 +90,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
allow_gen_future,
generics_def_id_map: Default::default(),
host_param_id: None,
effect_context: None,
};
lctx.with_hir_id_owner(owner, |lctx| f(lctx));

Expand Down Expand Up @@ -150,7 +150,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
lctx.is_in_trait_impl = impl_.of_trait.is_some();
}
hir::ItemKind::Trait(_, _, generics, _, _) if lctx.tcx.features().effects => {
lctx.host_param_id = generics
lctx.effect_context = generics
.params
.iter()
.find(|param| {
Expand All @@ -160,7 +160,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
.iter()
.any(|attr| attr.has_name(sym::rustc_host))
})
.map(|param| param.def_id);
.map(|param| EffectContext::Parametrized { host_param_id: param.def_id });
}
_ => {}
}
Expand Down Expand Up @@ -256,7 +256,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
let (generics, (ty, body_id)) = self.lower_generics(
generics,
Const::No,
Constness::Always,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_const_item(ty, span, expr.as_deref()),
Expand Down Expand Up @@ -286,11 +286,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
);

let itctx = ImplTraitContext::Universal;
let (generics, decl) =
this.lower_generics(generics, header.constness, id, &itctx, |this| {
let (generics, decl) = this.lower_generics(
generics,
header.constness.into(),
id,
&itctx,
|this| {
let ret_id = asyncness.opt_return_id();
this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id)
});
},
);
let sig = hir::FnSig {
decl,
header: this.lower_fn_header(*header),
Expand Down Expand Up @@ -325,7 +330,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
add_ty_alias_where_clause(&mut generics, *where_clauses, true);
let (generics, ty) = self.lower_generics(
&generics,
Const::No,
Constness::Never,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
Expand All @@ -347,7 +352,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::Enum(enum_definition, generics) => {
let (generics, variants) = self.lower_generics(
generics,
Const::No,
Constness::Never,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
Expand All @@ -361,7 +366,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::Struct(struct_def, generics) => {
let (generics, struct_def) = self.lower_generics(
generics,
Const::No,
Constness::Never,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, struct_def),
Expand All @@ -371,7 +376,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::Union(vdata, generics) => {
let (generics, vdata) = self.lower_generics(
generics,
Const::No,
Constness::Never,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| this.lower_variant_data(hir_id, vdata),
Expand Down Expand Up @@ -403,7 +408,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// parent lifetime.
let itctx = ImplTraitContext::Universal;
let (generics, (trait_ref, lowered_ty)) =
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
self.lower_generics(ast_generics, (*constness).into(), id, &itctx, |this| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref(
*constness,
Expand Down Expand Up @@ -449,7 +454,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
.unwrap_or(&[])
.iter()
.find(|x| x.has_name(sym::const_trait))
.map_or(Const::No, |x| Const::Yes(x.span));
.map_or(Constness::Never, |x| Constness::Maybe(x.span));
let (generics, (unsafety, items, bounds)) = self.lower_generics(
generics,
constness,
Expand All @@ -472,7 +477,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::TraitAlias(generics, bounds) => {
let (generics, bounds) = self.lower_generics(
generics,
Const::No,
Constness::Never,
id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
Expand Down Expand Up @@ -627,7 +632,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let fdec = &sig.decl;
let itctx = ImplTraitContext::Universal;
let (generics, (fn_dec, fn_args)) =
self.lower_generics(generics, Const::No, i.id, &itctx, |this| {
self.lower_generics(generics, Constness::Never, i.id, &itctx, |this| {
(
// Disallow `impl Trait` in foreign items.
this.lower_fn_decl(
Expand Down Expand Up @@ -746,7 +751,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => {
let (generics, kind) = self.lower_generics(
&generics,
Const::No,
Constness::Always,
i.id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
Expand Down Expand Up @@ -791,7 +796,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
let (generics, kind) = self.lower_generics(
&generics,
Const::No,
Constness::Never,
i.id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
Expand Down Expand Up @@ -859,7 +864,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let (generics, kind) = match &i.kind {
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
&generics,
Const::No,
Constness::Always,
i.id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
Expand Down Expand Up @@ -895,7 +900,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
add_ty_alias_where_clause(&mut generics, *where_clauses, false);
self.lower_generics(
&generics,
Const::No,
Constness::Never,
i.id,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| match ty {
Expand Down Expand Up @@ -1255,7 +1260,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let header = self.lower_fn_header(sig.header);
let itctx = ImplTraitContext::Universal;
let (generics, decl) =
self.lower_generics(generics, sig.header.constness, id, &itctx, |this| {
self.lower_generics(generics, sig.header.constness.into(), id, &itctx, |this| {
this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async)
});
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
Expand Down Expand Up @@ -1333,7 +1338,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_generics<T>(
&mut self,
generics: &Generics,
constness: Const,
constness: Constness,
parent_node_id: NodeId,
itctx: &ImplTraitContext,
f: impl FnOnce(&mut Self) -> T,
Expand Down Expand Up @@ -1387,7 +1392,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Desugar `~const` bound in generics into an additional `const host: bool` param
// if the effects feature is enabled. This needs to be done before we lower where
// clauses since where clauses need to bind to the DefId of the host param
let host_param_parts = if let Const::Yes(span) = constness
let host_param_parts = if let Constness::Maybe(span) = constness
&& self.tcx.features().effects
{
if let Some(param) =
Expand All @@ -1396,7 +1401,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
// user has manually specified a `rustc_host` param, in this case, we set
// the param id so that lowering logic can use that. But we don't create
// another host param, so this gives `None`.
self.host_param_id = Some(self.local_def_id(param.id));
self.effect_context = Some(EffectContext::Parametrized {
host_param_id: self.local_def_id(param.id),
});
None
} else {
let param_node_id = self.next_node_id();
Expand All @@ -1407,13 +1414,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
DefPathData::TypeNs(sym::host),
span,
);
self.host_param_id = Some(def_id);
self.effect_context = Some(EffectContext::Parametrized {
host_param_id: def_id,
});
Some((span, hir_id, def_id))
}
} else {
None
};

// FIXME(generic_const_items, effects): Instead of interpreting `~const` bounds as `const`
// bounds, we could introduce `const` bounds into the surface language.
if let Constness::Always = constness && self.tcx.features().effects {
self.effect_context = Some(EffectContext::Invariant { value: false });
};

let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
predicates.extend(generics.params.iter().filter_map(|param| {
self.lower_generic_bound_predicate(
Expand Down Expand Up @@ -1660,3 +1675,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
}

#[derive(Debug)]
enum Constness {
Always,
Maybe(Span),
Never,
}

impl From<Const> for Constness {
fn from(constness: Const) -> Self {
match constness {
Const::Yes(span) => Self::Maybe(span),
Const::No => Self::Never,
}
}
}
48 changes: 29 additions & 19 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ struct LoweringContext<'a, 'hir> {
/// field from the original parameter 'a to the new parameter 'a1.
generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,

host_param_id: Option<LocalDefId>,
effect_context: Option<EffectContext>,
}

trait ResolverAstLoweringExt {
Expand Down Expand Up @@ -227,6 +227,12 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
}
}

#[derive(Clone, Copy)]
enum EffectContext {
Parametrized { host_param_id: LocalDefId },
Invariant { value: bool },
Copy link
Member Author

@fmease fmease Nov 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I struggle a bit with the modelling of this variant. I know that Invariant { value: true } is super useless and that I should probably make it into a unit variant. However, I don't know what I should name it. I don't know if EffectContext should mention const-specific stuff, I opted against it. Otherwise, AlwaysConst would be the most obvious choice.

}

/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
/// and if so, what meaning it has.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -2476,34 +2482,38 @@ impl<'hir> GenericArgsCtor<'hir> {

// if bound is non-const, don't add host effect param
let ast::Const::Yes(span) = constness else { return };

let span = lcx.lower_span(span);

let id = lcx.next_node_id();
let hir_id = lcx.next_id();

let Some(host_param_id) = lcx.host_param_id else {
lcx.tcx
.sess
.delay_span_bug(span, "no host param id for call in const yet no errors reported");
let Some(context) = lcx.effect_context else {
lcx.tcx.sess.delay_span_bug(span, "no effect context for maybe-const trait bound");
return;
};

let body = lcx.lower_body(|lcx| {
(&[], {
let hir_id = lcx.next_id();
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
None,
lcx.arena.alloc(hir::Path {
span,
res,
segments: arena_vec![lcx; hir::PathSegment::new(Ident {
name: sym::host,
span,
}, hir_id, res)],
}),
));
let expr_kind = match context {
EffectContext::Parametrized { host_param_id } => {
let hir_id = lcx.next_id();
let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
hir::ExprKind::Path(hir::QPath::Resolved(
None,
lcx.arena.alloc(hir::Path {
span,
res,
segments: arena_vec![lcx; hir::PathSegment::new(Ident {
name: sym::host,
span,
}, hir_id, res)],
}),
))
}
EffectContext::Invariant { value } => hir::ExprKind::Lit(
lcx.arena.alloc(hir::Lit { node: LitKind::Bool(value), span }),
),
};
lcx.expr(span, expr_kind)
})
});
Expand Down
17 changes: 13 additions & 4 deletions tests/ui/generic-const-items/const-trait-impl.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
// known-bug: #110395
// FIXME check-pass
// check-pass

// Test that we can call methods from const trait impls inside of generic const items.
// `~const` bounds are interpreted as `const` bounds.

#![feature(generic_const_items, const_trait_impl)]
#![feature(generic_const_items, const_trait_impl, effects)]
#![allow(incomplete_features)]
#![crate_type = "lib"]

// FIXME(generic_const_items): Interpret `~const` as always-const.
const CREATE<T: ~const Create>: T = T::create();

pub const K0: i32 = CREATE::<i32>;
pub const K1: i32 = CREATE; // arg inferred

trait Mod { // doesn't need to be a `#[const_trait]`
const CREATE<T: ~const Create>: T;
}

impl Mod for () {
const CREATE<T: ~const Create>: T = T::create();
}

pub const K2: i32 = <() as Mod>::CREATE::<i32>;

#[const_trait]
trait Create {
fn create() -> Self;
Expand Down
11 changes: 0 additions & 11 deletions tests/ui/generic-const-items/const-trait-impl.stderr

This file was deleted.

Loading