1
Fork 0

Add #[rustc_legacy_const_generics]

This commit is contained in:
Amanieu d'Antras 2021-02-23 15:12:28 +00:00
parent 9b471a3f5f
commit d87eec1bf6
11 changed files with 310 additions and 2 deletions

View file

@ -9,7 +9,9 @@ use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::definitions::DefPathData;
use rustc_session::parse::feature_err;
use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP};
@ -42,8 +44,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
ExprKind::Call(ref f, ref args) => {
let f = self.lower_expr(f);
hir::ExprKind::Call(f, self.lower_exprs(args))
if let Some(legacy_args) = self.legacy_const_generic_args(f) {
self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args)
} else {
let f = self.lower_expr(f);
hir::ExprKind::Call(f, self.lower_exprs(args))
}
}
ExprKind::MethodCall(ref seg, ref args, span) => {
let hir_seg = self.arena.alloc(self.lower_path_segment(
@ -292,6 +298,86 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
/// Checks if an expression refers to a function marked with
/// `#[rustc_legacy_const_generics]` and returns the argument index list
/// from the attribute.
fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
if let ExprKind::Path(None, path) = &expr.kind {
if path.segments.last().unwrap().args.is_some() {
return None;
}
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
if partial_res.unresolved_segments() != 0 {
return None;
}
if let Res::Def(hir::def::DefKind::Fn, def_id) = partial_res.base_res() {
let attrs = self.item_attrs(def_id);
let attr = attrs
.iter()
.find(|a| self.sess.check_name(a, sym::rustc_legacy_const_generics))?;
let mut ret = vec![];
for meta in attr.meta_item_list()? {
match meta.literal()?.kind {
LitKind::Int(a, _) => {
ret.push(a as usize);
}
_ => panic!("invalid arg index"),
}
}
return Some(ret);
}
}
}
None
}
fn lower_legacy_const_generics(
&mut self,
mut f: Expr,
args: Vec<AstP<Expr>>,
legacy_args_idx: &[usize],
) -> hir::ExprKind<'hir> {
let path = match f.kind {
ExprKind::Path(None, ref mut path) => path,
_ => unreachable!(),
};
// Split the arguments into const generics and normal arguments
let mut real_args = vec![];
let mut generic_args = vec![];
for (idx, arg) in args.into_iter().enumerate() {
if legacy_args_idx.contains(&idx) {
let parent_def_id = self.current_hir_id_owner.last().unwrap().0;
let node_id = self.resolver.next_node_id();
// Add a definition for the in-band const def.
self.resolver.create_def(
parent_def_id,
node_id,
DefPathData::AnonConst,
ExpnId::root(),
arg.span,
);
let anon_const = AnonConst { id: node_id, value: arg };
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
} else {
real_args.push(arg);
}
}
// Add generic args to the last element of the path
path.segments.last_mut().unwrap().args =
Some(AstP(GenericArgs::AngleBracketed(AngleBracketedArgs {
span: DUMMY_SP,
args: generic_args,
})));
// Now lower everything as normal.
let f = self.lower_expr(&f);
hir::ExprKind::Call(f, self.lower_exprs(&real_args))
}
/// Emit an error and lower `ast::ExprKind::Let(pat, scrutinee)` into:
/// ```rust
/// match scrutinee { pats => true, _ => false }