Skip to content

Commit f8a29bd

Browse files
committed
Auto merge of rust-lang#94875 - matthiaskrgr:rollup-tq1li2d, r=matthiaskrgr
Rollup of 3 pull requests Successful merges: - rust-lang#94150 (rustdoc-json: Include GenericParamDefKind::Type::synthetic in JSON) - rust-lang#94833 ([2/2] Implement macro meta-variable expression) - rust-lang#94863 (Remove redundant slicing of whole ranges in `bootstrap`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 012720f + 49e0137 commit f8a29bd

File tree

12 files changed

+905
-103
lines changed

12 files changed

+905
-103
lines changed

compiler/rustc_expand/src/mbe/transcribe.rs

+147-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use crate::base::ExtCtxt;
2-
use crate::mbe;
32
use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
4-
3+
use crate::mbe::{self, MetaVarExpr};
54
use rustc_ast::mut_visit::{self, MutVisitor};
6-
use rustc_ast::token::{self, NtTT, Token};
5+
use rustc_ast::token::{self, NtTT, Token, TokenKind};
76
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing};
87
use rustc_data_structures::fx::FxHashMap;
98
use rustc_data_structures::sync::Lrc;
109
use rustc_errors::{pluralize, PResult};
10+
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
1111
use rustc_span::hygiene::{LocalExpnId, Transparency};
12-
use rustc_span::symbol::MacroRulesNormalizedIdent;
12+
use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
1313
use rustc_span::Span;
1414

1515
use smallvec::{smallvec, SmallVec};
@@ -411,13 +411,150 @@ fn lockstep_iter_size(
411411
}
412412
}
413413

414+
/// Used solely by the `count` meta-variable expression, counts the outer-most repetitions at a
415+
/// given optional nested depth.
416+
///
417+
/// For example, a macro parameter of `$( { $( $foo:ident ),* } )*` called with `{ a, b } { c }`:
418+
///
419+
/// * `[ $( ${count(foo)} ),* ]` will return [2, 1] with a, b = 2 and c = 1
420+
/// * `[ $( ${count(foo, 0)} ),* ]` will be the same as `[ $( ${count(foo)} ),* ]`
421+
/// * `[ $( ${count(foo, 1)} ),* ]` will return an error because `${count(foo, 1)}` is
422+
/// declared inside a single repetition and the index `1` implies two nested repetitions.
423+
fn count_repetitions<'a>(
424+
cx: &ExtCtxt<'a>,
425+
depth_opt: Option<usize>,
426+
mut matched: &NamedMatch,
427+
repeats: &[(usize, usize)],
428+
sp: &DelimSpan,
429+
) -> PResult<'a, usize> {
430+
// Recursively count the number of matches in `matched` at given depth
431+
// (or at the top-level of `matched` if no depth is given).
432+
fn count<'a>(
433+
cx: &ExtCtxt<'a>,
434+
declared_lhs_depth: usize,
435+
depth_opt: Option<usize>,
436+
matched: &NamedMatch,
437+
sp: &DelimSpan,
438+
) -> PResult<'a, usize> {
439+
match matched {
440+
MatchedNonterminal(_) => {
441+
if declared_lhs_depth == 0 {
442+
return Err(cx.struct_span_err(
443+
sp.entire(),
444+
"`count` can not be placed inside the inner-most repetition",
445+
));
446+
}
447+
match depth_opt {
448+
None => Ok(1),
449+
Some(_) => Err(out_of_bounds_err(cx, declared_lhs_depth, sp.entire(), "count")),
450+
}
451+
}
452+
MatchedSeq(ref named_matches) => {
453+
let new_declared_lhs_depth = declared_lhs_depth + 1;
454+
match depth_opt {
455+
None => named_matches
456+
.iter()
457+
.map(|elem| count(cx, new_declared_lhs_depth, None, elem, sp))
458+
.sum(),
459+
Some(0) => Ok(named_matches.len()),
460+
Some(depth) => named_matches
461+
.iter()
462+
.map(|elem| count(cx, new_declared_lhs_depth, Some(depth - 1), elem, sp))
463+
.sum(),
464+
}
465+
}
466+
}
467+
}
468+
// `repeats` records all of the nested levels at which we are currently
469+
// matching meta-variables. The meta-var-expr `count($x)` only counts
470+
// matches that occur in this "subtree" of the `NamedMatch` where we
471+
// are currently transcribing, so we need to descend to that subtree
472+
// before we start counting. `matched` contains the various levels of the
473+
// tree as we descend, and its final value is the subtree we are currently at.
474+
for &(idx, _) in repeats {
475+
if let MatchedSeq(ref ads) = matched {
476+
matched = &ads[idx];
477+
}
478+
}
479+
count(cx, 0, depth_opt, matched, sp)
480+
}
481+
482+
/// Returns a `NamedMatch` item declared on the RHS given an arbitrary [Ident]
483+
fn matched_from_ident<'ctx, 'interp, 'rslt>(
484+
cx: &ExtCtxt<'ctx>,
485+
ident: Ident,
486+
interp: &'interp FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
487+
) -> PResult<'ctx, &'rslt NamedMatch>
488+
where
489+
'interp: 'rslt,
490+
{
491+
let span = ident.span;
492+
let key = MacroRulesNormalizedIdent::new(ident);
493+
interp.get(&key).ok_or_else(|| {
494+
cx.struct_span_err(
495+
span,
496+
&format!("variable `{}` is not recognized in meta-variable expression", key),
497+
)
498+
})
499+
}
500+
501+
/// Used by meta-variable expressions when an user input is out of the actual declared bounds. For
502+
/// example, index(999999) in an repetition of only three elements.
503+
fn out_of_bounds_err<'a>(
504+
cx: &ExtCtxt<'a>,
505+
max: usize,
506+
span: Span,
507+
ty: &str,
508+
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
509+
cx.struct_span_err(span, &format!("{ty} depth must be less than {max}"))
510+
}
511+
414512
fn transcribe_metavar_expr<'a>(
415-
_cx: &ExtCtxt<'a>,
416-
_expr: mbe::MetaVarExpr,
417-
_interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
418-
_repeats: &[(usize, usize)],
419-
_result: &mut Vec<TreeAndSpacing>,
420-
_sp: &DelimSpan,
513+
cx: &ExtCtxt<'a>,
514+
expr: MetaVarExpr,
515+
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
516+
repeats: &[(usize, usize)],
517+
result: &mut Vec<TreeAndSpacing>,
518+
sp: &DelimSpan,
421519
) -> PResult<'a, ()> {
520+
match expr {
521+
MetaVarExpr::Count(original_ident, depth_opt) => {
522+
let matched = matched_from_ident(cx, original_ident, interp)?;
523+
let count = count_repetitions(cx, depth_opt, matched, &repeats, sp)?;
524+
let tt = TokenTree::token(
525+
TokenKind::lit(token::Integer, sym::integer(count), None),
526+
sp.entire(),
527+
);
528+
result.push(tt.into());
529+
}
530+
MetaVarExpr::Ignore(original_ident) => {
531+
// Used to ensure that `original_ident` is present in the LHS
532+
let _ = matched_from_ident(cx, original_ident, interp)?;
533+
}
534+
MetaVarExpr::Index(depth) => match repeats.iter().nth_back(depth) {
535+
Some((index, _)) => {
536+
result.push(
537+
TokenTree::token(
538+
TokenKind::lit(token::Integer, sym::integer(*index), None),
539+
sp.entire(),
540+
)
541+
.into(),
542+
);
543+
}
544+
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "index")),
545+
},
546+
MetaVarExpr::Length(depth) => match repeats.iter().nth_back(depth) {
547+
Some((_, length)) => {
548+
result.push(
549+
TokenTree::token(
550+
TokenKind::lit(token::Integer, sym::integer(*length), None),
551+
sp.entire(),
552+
)
553+
.into(),
554+
);
555+
}
556+
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "length")),
557+
},
558+
}
422559
Ok(())
423560
}

src/bootstrap/setup.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,9 @@ fn rustup_installed() -> bool {
161161
}
162162

163163
fn stage_dir_exists(stage_path: &str) -> bool {
164-
match fs::create_dir(&stage_path[..]) {
164+
match fs::create_dir(&stage_path) {
165165
Ok(_) => true,
166-
Err(_) => Path::new(&stage_path[..]).exists(),
166+
Err(_) => Path::new(&stage_path).exists(),
167167
}
168168
}
169169

@@ -179,7 +179,7 @@ fn attempt_toolchain_link(stage_path: &str) {
179179
return;
180180
}
181181

182-
if try_link_toolchain(&stage_path[..]) {
182+
if try_link_toolchain(&stage_path) {
183183
println!(
184184
"Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"
185185
);
@@ -188,7 +188,7 @@ fn attempt_toolchain_link(stage_path: &str) {
188188
println!(
189189
"To manually link stage 1 build to `stage1` toolchain, run:\n
190190
`rustup toolchain link stage1 {}`",
191-
&stage_path[..]
191+
&stage_path
192192
);
193193
}
194194
}
@@ -222,7 +222,7 @@ fn toolchain_is_linked() -> bool {
222222
fn try_link_toolchain(stage_path: &str) -> bool {
223223
Command::new("rustup")
224224
.stdout(std::process::Stdio::null())
225-
.args(&["toolchain", "link", "stage1", &stage_path[..]])
225+
.args(&["toolchain", "link", "stage1", &stage_path])
226226
.output()
227227
.map_or(false, |output| output.status.success())
228228
}

src/librustdoc/json/conversions.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,10 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
340340
Lifetime { outlives } => GenericParamDefKind::Lifetime {
341341
outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(),
342342
},
343-
Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type {
343+
Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type {
344344
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
345345
default: default.map(|x| (*x).into_tcx(tcx)),
346+
synthetic,
346347
},
347348
Const { did: _, ty, default } => {
348349
GenericParamDefKind::Const { ty: (*ty).into_tcx(tcx), default: default.map(|x| *x) }

src/rustdoc-json-types/lib.rs

+36-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::path::PathBuf;
99
use serde::{Deserialize, Serialize};
1010

1111
/// rustdoc format-version.
12-
pub const FORMAT_VERSION: u32 = 12;
12+
pub const FORMAT_VERSION: u32 = 13;
1313

1414
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
1515
/// about the language items in the local crate, as well as info about external items to allow
@@ -346,9 +346,41 @@ pub struct GenericParamDef {
346346
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
347347
#[serde(rename_all = "snake_case")]
348348
pub enum GenericParamDefKind {
349-
Lifetime { outlives: Vec<String> },
350-
Type { bounds: Vec<GenericBound>, default: Option<Type> },
351-
Const { ty: Type, default: Option<String> },
349+
Lifetime {
350+
outlives: Vec<String>,
351+
},
352+
Type {
353+
bounds: Vec<GenericBound>,
354+
default: Option<Type>,
355+
/// This is normally `false`, which means that this generic parameter is
356+
/// declared in the Rust source text.
357+
///
358+
/// If it is `true`, this generic parameter has been introduced by the
359+
/// compiler behind the scenes.
360+
///
361+
/// # Example
362+
///
363+
/// Consider
364+
///
365+
/// ```ignore (pseudo-rust)
366+
/// pub fn f(_: impl Trait) {}
367+
/// ```
368+
///
369+
/// The compiler will transform this behind the scenes to
370+
///
371+
/// ```ignore (pseudo-rust)
372+
/// pub fn f<impl Trait: Trait>(_: impl Trait) {}
373+
/// ```
374+
///
375+
/// In this example, the generic parameter named `impl Trait` (and which
376+
/// is bound by `Trait`) is synthetic, because it was not originally in
377+
/// the Rust source text.
378+
synthetic: bool,
379+
},
380+
Const {
381+
ty: Type,
382+
default: Option<String>,
383+
},
352384
}
353385

354386
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]

src/test/rustdoc-json/fns/generics.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// ignore-tidy-linelength
2+
3+
#![feature(no_core)]
4+
#![no_core]
5+
6+
// @set wham_id = generics.json "$.index[*][?(@.name=='Wham')].id"
7+
pub trait Wham {}
8+
9+
// @is - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.where_predicates" []
10+
// @count - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[*]" 1
11+
// @is - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].name" '"T"'
12+
// @has - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" false
13+
// @has - "$.index[*][?(@.name=='one_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" $wham_id
14+
// @is - "$.index[*][?(@.name=='one_generic_param_fn')].inner.decl.inputs" '[["w", {"inner": "T", "kind": "generic"}]]'
15+
pub fn one_generic_param_fn<T: Wham>(w: T) {}
16+
17+
// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.where_predicates" []
18+
// @count - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[*]" 1
19+
// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].name" '"impl Wham"'
20+
// @has - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.synthetic" true
21+
// @has - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.generics.params[0].kind.type.bounds[0].trait_bound.trait.inner.id" $wham_id
22+
// @count - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[*]" 1
23+
// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][0]" '"w"'
24+
// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][1].kind" '"impl_trait"'
25+
// @is - "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.decl.inputs[0][1].inner[0].trait_bound.trait.inner.id" $wham_id
26+
pub fn one_synthetic_generic_param_fn(w: impl Wham) {}

0 commit comments

Comments
 (0)