1.0.23升级至1.0.35

Signed-off-by: 徐未来 <xuweilai2@huawei.com>
This commit is contained in:
徐未来 2024-04-02 17:14:09 +08:00
parent 15cdde10b6
commit a27120161a
31 changed files with 356 additions and 477 deletions

1
.cargo-ok Normal file
View File

@ -0,0 +1 @@
ok

6
.cargo_vcs_info.json Normal file
View File

@ -0,0 +1,6 @@
{
"git": {
"sha1": "b01743f24cb5b19f96a3eac6bce0e7aee10f6199"
},
"path_in_vcs": ""
}

View File

@ -1 +0,0 @@
msrv = "1.31.0"

View File

@ -3,6 +3,7 @@ name: CI
on:
push:
pull_request:
workflow_dispatch:
schedule: [cron: "40 1 * * *"]
permissions:
@ -12,45 +13,58 @@ env:
RUSTFLAGS: -Dwarnings
jobs:
pre_ci:
uses: dtolnay/.github/.github/workflows/pre_ci.yml@master
test:
name: Rust ${{matrix.rust}}
needs: pre_ci
if: needs.pre_ci.outputs.continue
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
rust: [stable, beta, 1.56.0]
rust: [nightly, stable, beta, 1.56.0]
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{matrix.rust}}
components: rust-src
- name: Enable type layout randomization
run: echo RUSTFLAGS=${RUSTFLAGS}\ -Zrandomize-layout >> $GITHUB_ENV
if: matrix.rust == 'nightly'
- run: cargo test
- run: cargo run --manifest-path benches/Cargo.toml
nightly:
name: Rust nightly
minimal:
name: Minimal versions
needs: pre_ci
if: needs.pre_ci.outputs.continue
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- run: cargo generate-lockfile -Z minimal-versions
- run: cargo check --locked
doc:
name: Documentation
needs: pre_ci
if: needs.pre_ci.outputs.continue
runs-on: ubuntu-latest
timeout-minutes: 45
env:
RUSTDOCFLAGS: -Dwarnings
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: rust-src
- run: cargo test
- run: cargo update -Z minimal-versions
- run: cargo build
msrv:
name: Rust 1.31.0
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@1.31.0
with:
components: rust-src
- run: cargo check
- uses: dtolnay/install@cargo-docs-rs
- run: cargo docs-rs
clippy:
name: Clippy
@ -58,19 +72,22 @@ jobs:
if: github.event_name != 'pull_request'
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
with:
components: clippy, rust-src
- run: cargo clippy --tests -- -Dclippy::all -Dclippy::pedantic
- run: cargo clippy --tests --workspace -- -Dclippy::all -Dclippy::pedantic
miri:
name: Miri
needs: pre_ci
if: needs.pre_ci.outputs.continue
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@miri
- run: cargo miri setup
- run: cargo miri test
env:
MIRIFLAGS: -Zmiri-strict-provenance
@ -81,6 +98,6 @@ jobs:
if: github.event_name != 'pull_request'
timeout-minutes: 45
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: dtolnay/install@cargo-outdated
- run: cargo outdated --workspace --exit-code 1

View File

@ -14,18 +14,16 @@
import("//build/ohos.gni")
ohos_cargo_crate("lib") {
crate_name = "quote"
crate_type = "rlib"
crate_root = "src/lib.rs"
crate_name = "quote"
crate_type = "rlib"
crate_root = "src/lib.rs"
sources = ["src/lib.rs"]
edition = "2018"
cargo_pkg_version = "1.0.23"
cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
cargo_pkg_name = "quote"
cargo_pkg_description = "Quasi-quoting macro quote!(...)"
deps = ["//third_party/rust/crates/proc-macro2:lib"]
features = ["proc-macro"]
build_root = "build.rs"
build_sources = ["build.rs"]
sources = [ "src/lib.rs" ]
edition = "2018"
cargo_pkg_version = "1.0.35"
cargo_pkg_authors = "David Tolnay <dtolnay@gmail.com>"
cargo_pkg_name = "quote"
cargo_pkg_description = "Quasi-quoting macro quote!(...)"
deps = [ "//third_party/rust/crates/proc-macro2:lib" ]
features = [ "proc-macro" ]
}

View File

@ -1,35 +1,50 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
rust-version = "1.56"
name = "quote"
version = "1.0.23" # don't forget to update html_root_url, version in readme for breaking changes
version = "1.0.35"
authors = ["David Tolnay <dtolnay@gmail.com>"]
autobenches = false
categories = ["development-tools::procedural-macro-helpers"]
description = "Quasi-quoting macro quote!(...)"
documentation = "https://docs.rs/quote/"
edition = "2018"
keywords = ["macros", "syn"]
readme = "README.md"
keywords = [
"macros",
"syn",
]
categories = ["development-tools::procedural-macro-helpers"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/dtolnay/quote"
rust-version = "1.31"
[dependencies]
proc-macro2 = { version = "1.0.40", default-features = false }
[dev-dependencies]
rustversion = "1.0"
trybuild = { version = "1.0.66", features = ["diff"] }
[features]
default = ["proc-macro"]
# Disabling the proc-macro feature removes the dynamic library dependency on
# libproc_macro in the rustc compiler.
proc-macro = ["proc-macro2/proc-macro"]
[package.metadata.docs.rs]
rustdoc-args = ["--generate-link-to-definition"]
targets = ["x86_64-unknown-linux-gnu"]
[lib]
doc-scrape-examples = false
[workspace]
members = ["benches"]
[dependencies.proc-macro2]
version = "1.0.74"
default-features = false
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dev-dependencies.rustversion]
version = "1.0"
[dev-dependencies.trybuild]
version = "1.0.66"
features = ["diff"]
[features]
default = ["proc-macro"]
proc-macro = ["proc-macro2/proc-macro"]

36
Cargo.toml.orig Normal file
View File

@ -0,0 +1,36 @@
[package]
name = "quote"
version = "1.0.35" # don't forget to update html_root_url, version in readme for breaking changes
authors = ["David Tolnay <dtolnay@gmail.com>"]
autobenches = false
categories = ["development-tools::procedural-macro-helpers"]
description = "Quasi-quoting macro quote!(...)"
documentation = "https://docs.rs/quote/"
edition = "2018"
keywords = ["macros", "syn"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/dtolnay/quote"
rust-version = "1.56"
[dependencies]
proc-macro2 = { version = "1.0.74", default-features = false }
[dev-dependencies]
rustversion = "1.0"
trybuild = { version = "1.0.66", features = ["diff"] }
[features]
default = ["proc-macro"]
# Disabling the proc-macro feature removes the dynamic library dependency on
# libproc_macro in the rustc compiler.
proc-macro = ["proc-macro2/proc-macro"]
[lib]
doc-scrape-examples = false
[workspace]
members = ["benches"]
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
rustdoc-args = ["--generate-link-to-definition"]

View File

@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -3,7 +3,7 @@
"Name": "quote",
"License": "Apache License V2.0, MIT",
"License File": "LICENSE-APACHE, LICENSE-MIT",
"Version Number": "1.0.23",
"Version Number": "1.0.35",
"Owner": "fangting12@huawei.com",
"Upstream URL": "https://github.com/dtolnay/quote",
"Description": "A Rust library that provides support for generating Rust code."

View File

@ -34,7 +34,7 @@ macros.
quote = "1.0"
```
*Version requirement: Quote supports rustc 1.31 and up.*<br>
*Version requirement: Quote supports rustc 1.56 and up.*<br>
[*Release notes*](https://github.com/dtolnay/quote/releases)
<br>
@ -233,15 +233,26 @@ macro.
## Non-macro code generators
When using `quote` in a build.rs or main.rs and writing the output out to a
file, consider having the code generator pass the tokens through [rustfmt]
before writing (either by shelling out to the `rustfmt` binary or by pulling in
the `rustfmt` library as a dependency). This way if an error occurs in the
generated code it is convenient for a human to read and debug.
file, consider having the code generator pass the tokens through [prettyplease]
before writing. This way if an error occurs in the generated code it is
convenient for a human to read and debug.
Be aware that no kind of hygiene or span information is retained when tokens are
written to a file; the conversion from tokens to source code is lossy.
[rustfmt]: https://github.com/rust-lang/rustfmt
Example usage in build.rs:
```rust
let output = quote! { ... };
let syntax_tree = syn::parse2(output).unwrap();
let formatted = prettyplease::unparse(&syntax_tree);
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("out.rs");
fs::write(dest_path, formatted).unwrap();
```
[prettyplease]: https://github.com/dtolnay/prettyplease
<br>

View File

@ -1,20 +0,0 @@
[package]
name = "quote-benchmark"
version = "0.0.0"
authors = ["David Tolnay <dtolnay@gmail.com>"]
edition = "2018"
license = "MIT OR Apache-2.0"
publish = false
[lib]
proc-macro = true
path = "lib.rs"
[[bin]]
name = "quote-benchmark"
path = "main.rs"
[dependencies]
proc-macro2 = "1.0"
quote = { path = ".." }
termcolor = "1.1"

View File

@ -1,18 +0,0 @@
Example output:
<pre>
$ <b>cargo run && cargo run --release</b>
<i>Compiling quote v1.0.10</i>
<i>Compiling quote-benchmark v0.0.0</i>
<kbd><kbd><b>macro in debug mode: 1655 micros</b></kbd></kbd>
<i>Finished dev [unoptimized + debuginfo] target(s) in 4.39s</i>
<i>Running `/git/quote/target/debug/quote-benchmark`</i>
<kbd><kbd><b>non-macro in debug mode: 1205 micros</b></kbd></kbd>
<i>Compiling quote v1.0.10</i>
<i>Compiling quote-benchmark v0.0.0</i>
<kbd><kbd><b>macro in release mode: 1635 micros</b></kbd></kbd>
<i>Finished release [optimized] target(s) in 4.00s</i>
<i>Running `/git/quote/target/release/quote-benchmark`</i>
<kbd><kbd><b>non-macro in release mode: 105 micros</b></kbd></kbd>
</pre>

View File

@ -1,206 +0,0 @@
use quote::quote;
#[allow(unused_macros)]
macro_rules! benchmark {
(|$ident:ident| $quote:expr) => {
mod timer;
use proc_macro::TokenStream;
use proc_macro2::Ident;
#[proc_macro]
pub fn run_quote_benchmark(input: TokenStream) -> TokenStream {
let input = proc_macro2::TokenStream::from(input);
let span = input.into_iter().next().unwrap().span();
let $ident = Ident::new("Response", span);
timer::time("macro", || proc_macro::TokenStream::from($quote));
TokenStream::new()
}
};
}
#[allow(unused_imports)]
use benchmark;
crate::benchmark! {
|ident| quote! {
impl<'de> _serde::Deserialize<'de> for #ident {
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
where
__D: _serde::Deserializer<'de>,
{
#[allow(non_camel_case_types)]
enum __Field {
__field0,
__field1,
__ignore,
}
struct __FieldVisitor;
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
type Value = __Field;
fn expecting(
&self,
__formatter: &mut _serde::export::Formatter,
) -> _serde::export::fmt::Result {
_serde::export::Formatter::write_str(__formatter, "field identifier")
}
fn visit_u64<__E>(self, __value: u64) -> _serde::export::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
0u64 => _serde::export::Ok(__Field::__field0),
1u64 => _serde::export::Ok(__Field::__field1),
_ => _serde::export::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
&"field index 0 <= i < 2",
)),
}
}
fn visit_str<__E>(self, __value: &str) -> _serde::export::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
"id" => _serde::export::Ok(__Field::__field0),
"s" => _serde::export::Ok(__Field::__field1),
_ => _serde::export::Ok(__Field::__ignore),
}
}
fn visit_bytes<__E>(
self,
__value: &[u8],
) -> _serde::export::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
b"id" => _serde::export::Ok(__Field::__field0),
b"s" => _serde::export::Ok(__Field::__field1),
_ => _serde::export::Ok(__Field::__ignore),
}
}
}
impl<'de> _serde::Deserialize<'de> for __Field {
#[inline]
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
where
__D: _serde::Deserializer<'de>,
{
_serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor)
}
}
struct __Visitor<'de> {
marker: _serde::export::PhantomData<#ident>,
lifetime: _serde::export::PhantomData<&'de ()>,
}
impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
type Value = #ident;
fn expecting(
&self,
__formatter: &mut _serde::export::Formatter,
) -> _serde::export::fmt::Result {
_serde::export::Formatter::write_str(__formatter, "struct")
}
#[inline]
fn visit_seq<__A>(
self,
mut __seq: __A,
) -> _serde::export::Result<Self::Value, __A::Error>
where
__A: _serde::de::SeqAccess<'de>,
{
let __field0 =
match try!(_serde::de::SeqAccess::next_element::<u64>(&mut __seq)) {
_serde::export::Some(__value) => __value,
_serde::export::None => {
return _serde::export::Err(_serde::de::Error::invalid_length(
0usize,
&"struct with 2 elements",
));
}
};
let __field1 =
match try!(_serde::de::SeqAccess::next_element::<String>(&mut __seq)) {
_serde::export::Some(__value) => __value,
_serde::export::None => {
return _serde::export::Err(_serde::de::Error::invalid_length(
1usize,
&"struct with 2 elements",
));
}
};
_serde::export::Ok(#ident {
id: __field0,
s: __field1,
})
}
#[inline]
fn visit_map<__A>(
self,
mut __map: __A,
) -> _serde::export::Result<Self::Value, __A::Error>
where
__A: _serde::de::MapAccess<'de>,
{
let mut __field0: _serde::export::Option<u64> = _serde::export::None;
let mut __field1: _serde::export::Option<String> = _serde::export::None;
while let _serde::export::Some(__key) =
try!(_serde::de::MapAccess::next_key::<__Field>(&mut __map))
{
match __key {
__Field::__field0 => {
if _serde::export::Option::is_some(&__field0) {
return _serde::export::Err(
<__A::Error as _serde::de::Error>::duplicate_field("id"),
);
}
__field0 = _serde::export::Some(
try!(_serde::de::MapAccess::next_value::<u64>(&mut __map)),
);
}
__Field::__field1 => {
if _serde::export::Option::is_some(&__field1) {
return _serde::export::Err(
<__A::Error as _serde::de::Error>::duplicate_field("s"),
);
}
__field1 = _serde::export::Some(
try!(_serde::de::MapAccess::next_value::<String>(&mut __map)),
);
}
_ => {
let _ = try!(_serde::de::MapAccess::next_value::<
_serde::de::IgnoredAny,
>(&mut __map));
}
}
}
let __field0 = match __field0 {
_serde::export::Some(__field0) => __field0,
_serde::export::None => try!(_serde::private::de::missing_field("id")),
};
let __field1 = match __field1 {
_serde::export::Some(__field1) => __field1,
_serde::export::None => try!(_serde::private::de::missing_field("s")),
};
_serde::export::Ok(#ident {
id: __field0,
s: __field1,
})
}
}
const FIELDS: &'static [&'static str] = &["id", "s"];
_serde::Deserializer::deserialize_struct(
__deserializer,
stringify!(#ident),
FIELDS,
__Visitor {
marker: _serde::export::PhantomData::<#ident>,
lifetime: _serde::export::PhantomData,
},
)
}
}
}
}

View File

@ -1,25 +0,0 @@
quote_benchmark::run_quote_benchmark!(_);
mod benchmark {
macro_rules! benchmark {
(|$ident:ident| $quote:expr) => {
use proc_macro2::{Ident, Span};
pub fn quote() -> proc_macro2::TokenStream {
let $ident = Ident::new("Response", Span::call_site());
$quote
}
};
}
pub(crate) use benchmark;
}
use benchmark::benchmark;
mod lib;
mod timer;
fn main() {
timer::time("non-macro", lib::quote);
}

View File

@ -1,17 +0,0 @@
use std::io::Write;
use std::time::Instant;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
const ITERATIONS: u32 = 1000;
pub fn time<T>(name: &'static str, function: impl Fn() -> T) {
let begin = Instant::now();
for _ in 0..ITERATIONS {
_ = function();
}
let micros = (begin.elapsed() / ITERATIONS).as_micros();
let mode = ["release", "debug"][cfg!(debug_assertions) as usize];
let mut writer = StandardStream::stderr(ColorChoice::Auto);
_ = writer.set_color(ColorSpec::new().set_fg(Some(Color::Magenta)));
_ = writeln!(&mut writer, "{} in {} mode: {} micros", name, mode, micros);
}

View File

@ -1,38 +0,0 @@
use std::env;
use std::process::{self, Command};
use std::str;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let version = match rustc_version() {
Some(version) => version,
None => return,
};
if version.minor < 31 {
eprintln!("Minimum supported rustc version is 1.31");
process::exit(1);
}
if version.minor < 53 {
// https://github.com/rust-lang/rust/issues/43081
println!("cargo:rustc-cfg=needs_invalid_span_workaround");
}
}
struct RustcVersion {
minor: u32,
}
fn rustc_version() -> Option<RustcVersion> {
let rustc = env::var_os("RUSTC")?;
let output = Command::new(rustc).arg("--version").output().ok()?;
let version = str::from_utf8(&output.stdout).ok()?;
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return None;
}
let minor = pieces.next()?.parse().ok()?;
Some(RustcVersion { minor })
}

View File

@ -1,6 +1,6 @@
use alloc::borrow::Cow;
use core::fmt;
use proc_macro2::{Ident, Span};
use std::borrow::Cow;
/// Specialized formatting trait used by `format_ident!`.
///
@ -8,6 +8,8 @@ use std::borrow::Cow;
/// stripped, if present.
///
/// See [`format_ident!`] for more information.
///
/// [`format_ident!`]: crate::format_ident
pub trait IdentFragment {
/// Format this value as an identifier fragment.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
@ -47,8 +49,8 @@ impl IdentFragment for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let id = self.to_string();
if id.starts_with("r#") {
fmt::Display::fmt(&id[2..], f)
if let Some(id) = id.strip_prefix("r#") {
fmt::Display::fmt(id, f)
} else {
fmt::Display::fmt(&id[..], f)
}

View File

@ -79,9 +79,20 @@
//! }
//! };
//! ```
//!
//! <br>
//!
//! # Non-macro code generators
//!
//! When using `quote` in a build.rs or main.rs and writing the output out to a
//! file, consider having the code generator pass the tokens through
//! [prettyplease] before writing. This way if an error occurs in the generated
//! code it is convenient for a human to read and debug.
//!
//! [prettyplease]: https://github.com/dtolnay/prettyplease
// Quote types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/quote/1.0.23")]
#![doc(html_root_url = "https://docs.rs/quote/1.0.35")]
#![allow(
clippy::doc_markdown,
clippy::missing_errors_doc,
@ -91,10 +102,9 @@
clippy::wrong_self_convention,
)]
#[cfg(all(
not(all(target_arch = "wasm32", target_os = "unknown")),
feature = "proc-macro"
))]
extern crate alloc;
#[cfg(feature = "proc-macro")]
extern crate proc_macro;
mod ext;
@ -418,7 +428,7 @@ pub mod spanned;
/// appears suffixed as integer literals by interpolating them as [`syn::Index`]
/// instead.
///
/// [`syn::Index`]: https://docs.rs/syn/1.0/syn/struct.Index.html
/// [`syn::Index`]: https://docs.rs/syn/2.0/syn/struct.Index.html
///
/// ```compile_fail
/// let i = 0usize..self.fields.len();
@ -619,14 +629,14 @@ macro_rules! quote_spanned {
#[macro_export]
macro_rules! quote_spanned {
($span:expr=>) => {{
let _: $crate::__private::Span = $span;
let _: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
$crate::__private::TokenStream::new()
}};
// Special case rule for a single tt, for performance.
($span:expr=> $tt:tt) => {{
let mut _s = $crate::__private::TokenStream::new();
let _span: $crate::__private::Span = $span;
let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
$crate::quote_token_spanned!{$tt _s _span}
_s
}};
@ -634,13 +644,13 @@ macro_rules! quote_spanned {
// Special case rules for two tts, for performance.
($span:expr=> # $var:ident) => {{
let mut _s = $crate::__private::TokenStream::new();
let _: $crate::__private::Span = $span;
let _: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
$crate::ToTokens::to_tokens(&$var, &mut _s);
_s
}};
($span:expr=> $tt1:tt $tt2:tt) => {{
let mut _s = $crate::__private::TokenStream::new();
let _span: $crate::__private::Span = $span;
let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
$crate::quote_token_spanned!{$tt1 _s _span}
$crate::quote_token_spanned!{$tt2 _s _span}
_s
@ -649,7 +659,7 @@ macro_rules! quote_spanned {
// Rule for any other number of tokens.
($span:expr=> $($tt:tt)*) => {{
let mut _s = $crate::__private::TokenStream::new();
let _span: $crate::__private::Span = $span;
let _span: $crate::__private::Span = $crate::__private::get_span($span).__into_span();
$crate::quote_each_token_spanned!{_s _span $($tt)*}
_s
}};

View File

@ -1,13 +1,25 @@
use self::get_span::{GetSpan, GetSpanBase, GetSpanInner};
use crate::{IdentFragment, ToTokens, TokenStreamExt};
use core::fmt;
use core::iter;
use core::ops::BitOr;
use proc_macro2::{Group, Ident, Punct, Spacing, TokenTree};
#[doc(hidden)]
pub use alloc::format;
#[doc(hidden)]
pub use core::option::Option;
pub use proc_macro2::*;
pub use std::format;
#[doc(hidden)]
pub type Delimiter = proc_macro2::Delimiter;
#[doc(hidden)]
pub type Span = proc_macro2::Span;
#[doc(hidden)]
pub type TokenStream = proc_macro2::TokenStream;
#[doc(hidden)]
pub struct HasIterator; // True
#[doc(hidden)]
pub struct ThereIsNoIteratorInRepetition; // False
impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
@ -44,14 +56,16 @@ impl BitOr<HasIterator> for HasIterator {
/// These traits expose a `quote_into_iter` method which should allow calling
/// whichever impl happens to be applicable. Calling that method repeatedly on
/// the returned value should be idempotent.
#[doc(hidden)]
pub mod ext {
use super::RepInterp;
use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter};
use crate::ToTokens;
use alloc::collections::btree_set::{self, BTreeSet};
use core::slice;
use std::collections::btree_set::{self, BTreeSet};
/// Extension trait providing the `quote_into_iter` method on iterators.
#[doc(hidden)]
pub trait RepIteratorExt: Iterator + Sized {
fn quote_into_iter(self) -> (Self, HasIter) {
(self, HasIter)
@ -63,6 +77,7 @@ pub mod ext {
/// Extension trait providing the `quote_into_iter` method for
/// non-iterable types. These types interpolate the same value in each
/// iteration of the repetition.
#[doc(hidden)]
pub trait RepToTokensExt {
/// Pretend to be an iterator for the purposes of `quote_into_iter`.
/// This allows repeated calls to `quote_into_iter` to continue
@ -80,6 +95,7 @@ pub mod ext {
/// Extension trait providing the `quote_into_iter` method for types that
/// can be referenced as an iterator.
#[doc(hidden)]
pub trait RepAsIteratorExt<'q> {
type Iter: Iterator;
@ -138,6 +154,7 @@ pub mod ext {
// Helper type used within interpolations to allow for repeated binding names.
// Implements the relevant traits, and exports a dummy `next()` method.
#[derive(Copy, Clone)]
#[doc(hidden)]
pub struct RepInterp<T>(pub T);
impl<T> RepInterp<T> {
@ -164,10 +181,69 @@ impl<T: ToTokens> ToTokens for RepInterp<T> {
}
}
#[doc(hidden)]
#[inline]
pub fn get_span<T>(span: T) -> GetSpan<T> {
GetSpan(GetSpanInner(GetSpanBase(span)))
}
mod get_span {
use core::ops::Deref;
use proc_macro2::extra::DelimSpan;
use proc_macro2::Span;
pub struct GetSpan<T>(pub(crate) GetSpanInner<T>);
pub struct GetSpanInner<T>(pub(crate) GetSpanBase<T>);
pub struct GetSpanBase<T>(pub(crate) T);
impl GetSpan<Span> {
#[inline]
pub fn __into_span(self) -> Span {
((self.0).0).0
}
}
impl GetSpanInner<DelimSpan> {
#[inline]
pub fn __into_span(&self) -> Span {
(self.0).0.join()
}
}
impl<T> GetSpanBase<T> {
#[allow(clippy::unused_self)]
pub fn __into_span(&self) -> T {
unreachable!()
}
}
impl<T> Deref for GetSpan<T> {
type Target = GetSpanInner<T>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> Deref for GetSpanInner<T> {
type Target = GetSpanBase<T>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
}
#[doc(hidden)]
pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) {
tokens.append(Group::new(delimiter, inner));
}
#[doc(hidden)]
pub fn push_group_spanned(
tokens: &mut TokenStream,
span: Span,
@ -179,11 +255,13 @@ pub fn push_group_spanned(
tokens.append(g);
}
#[doc(hidden)]
pub fn parse(tokens: &mut TokenStream, s: &str) {
let s: TokenStream = s.parse().expect("invalid token stream");
tokens.extend(iter::once(s));
}
#[doc(hidden)]
pub fn parse_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
let s: TokenStream = s.parse().expect("invalid token stream");
tokens.extend(s.into_iter().map(|t| respan_token_tree(t, span)));
@ -206,15 +284,18 @@ fn respan_token_tree(mut token: TokenTree, span: Span) -> TokenTree {
token
}
#[doc(hidden)]
pub fn push_ident(tokens: &mut TokenStream, s: &str) {
let span = Span::call_site();
push_ident_spanned(tokens, span, s);
}
#[doc(hidden)]
pub fn push_ident_spanned(tokens: &mut TokenStream, span: Span, s: &str) {
tokens.append(ident_maybe_raw(s, span));
}
#[doc(hidden)]
pub fn push_lifetime(tokens: &mut TokenStream, lifetime: &str) {
struct Lifetime<'a> {
name: &'a str,
@ -245,6 +326,7 @@ pub fn push_lifetime(tokens: &mut TokenStream, lifetime: &str) {
});
}
#[doc(hidden)]
pub fn push_lifetime_spanned(tokens: &mut TokenStream, span: Span, lifetime: &str) {
struct Lifetime<'a> {
name: &'a str,
@ -281,9 +363,11 @@ pub fn push_lifetime_spanned(tokens: &mut TokenStream, span: Span, lifetime: &st
macro_rules! push_punct {
($name:ident $spanned:ident $char1:tt) => {
#[doc(hidden)]
pub fn $name(tokens: &mut TokenStream) {
tokens.append(Punct::new($char1, Spacing::Alone));
}
#[doc(hidden)]
pub fn $spanned(tokens: &mut TokenStream, span: Span) {
let mut punct = Punct::new($char1, Spacing::Alone);
punct.set_span(span);
@ -291,10 +375,12 @@ macro_rules! push_punct {
}
};
($name:ident $spanned:ident $char1:tt $char2:tt) => {
#[doc(hidden)]
pub fn $name(tokens: &mut TokenStream) {
tokens.append(Punct::new($char1, Spacing::Joint));
tokens.append(Punct::new($char2, Spacing::Alone));
}
#[doc(hidden)]
pub fn $spanned(tokens: &mut TokenStream, span: Span) {
let mut punct = Punct::new($char1, Spacing::Joint);
punct.set_span(span);
@ -305,11 +391,13 @@ macro_rules! push_punct {
}
};
($name:ident $spanned:ident $char1:tt $char2:tt $char3:tt) => {
#[doc(hidden)]
pub fn $name(tokens: &mut TokenStream) {
tokens.append(Punct::new($char1, Spacing::Joint));
tokens.append(Punct::new($char2, Spacing::Joint));
tokens.append(Punct::new($char3, Spacing::Alone));
}
#[doc(hidden)]
pub fn $spanned(tokens: &mut TokenStream, span: Span) {
let mut punct = Punct::new($char1, Spacing::Joint);
punct.set_span(span);
@ -369,24 +457,27 @@ push_punct!(push_star push_star_spanned '*');
push_punct!(push_sub push_sub_spanned '-');
push_punct!(push_sub_eq push_sub_eq_spanned '-' '=');
#[doc(hidden)]
pub fn push_underscore(tokens: &mut TokenStream) {
push_underscore_spanned(tokens, Span::call_site());
}
#[doc(hidden)]
pub fn push_underscore_spanned(tokens: &mut TokenStream, span: Span) {
tokens.append(Ident::new("_", span));
}
// Helper method for constructing identifiers from the `format_ident!` macro,
// handling `r#` prefixes.
#[doc(hidden)]
pub fn mk_ident(id: &str, span: Option<Span>) -> Ident {
let span = span.unwrap_or_else(Span::call_site);
ident_maybe_raw(id, span)
}
fn ident_maybe_raw(id: &str, span: Span) -> Ident {
if id.starts_with("r#") {
Ident::new_raw(&id[2..], span)
if let Some(id) = id.strip_prefix("r#") {
Ident::new_raw(id, span)
} else {
Ident::new(id, span)
}
@ -399,6 +490,7 @@ fn ident_maybe_raw(id: &str, span: Span) -> Ident {
// `Octal`, `LowerHex`, `UpperHex`, and `Binary` to allow for their use within
// `format_ident!`.
#[derive(Copy, Clone)]
#[doc(hidden)]
pub struct IdentFragmentAdapter<T: IdentFragment>(pub T);
impl<T: IdentFragment> IdentFragmentAdapter<T> {

View File

@ -1,7 +1,9 @@
use crate::ToTokens;
use proc_macro2::extra::DelimSpan;
use proc_macro2::{Span, TokenStream};
pub trait Spanned {
// Not public API other than via the syn crate. Use syn::spanned::Spanned.
pub trait Spanned: private::Sealed {
fn __span(&self) -> Span;
}
@ -11,6 +13,12 @@ impl Spanned for Span {
}
}
impl Spanned for DelimSpan {
fn __span(&self) -> Span {
self.join()
}
}
impl<T: ?Sized + ToTokens> Spanned for T {
fn __span(&self) -> Span {
join_spans(self.into_token_stream())
@ -18,20 +26,8 @@ impl<T: ?Sized + ToTokens> Spanned for T {
}
fn join_spans(tokens: TokenStream) -> Span {
#[cfg(not(needs_invalid_span_workaround))]
let mut iter = tokens.into_iter().map(|tt| tt.span());
#[cfg(needs_invalid_span_workaround)]
let mut iter = tokens.into_iter().filter_map(|tt| {
let span = tt.span();
let debug = format!("{:?}", span);
if debug.ends_with("bytes(0..0)") {
None
} else {
Some(span)
}
});
let first = match iter.next() {
Some(span) => span,
None => return Span::call_site(),
@ -41,3 +37,14 @@ fn join_spans(tokens: TokenStream) -> Span {
.and_then(|last| first.join(last))
.unwrap_or(first)
}
mod private {
use crate::ToTokens;
use proc_macro2::extra::DelimSpan;
use proc_macro2::Span;
pub trait Sealed {}
impl Sealed for Span {}
impl Sealed for DelimSpan {}
impl<T: ?Sized + ToTokens> Sealed for T {}
}

View File

@ -1,8 +1,8 @@
use super::TokenStreamExt;
use alloc::borrow::Cow;
use alloc::rc::Rc;
use core::iter;
use proc_macro2::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree};
use std::borrow::Cow;
use std::rc::Rc;
/// Types that can be interpolated inside a `quote!` invocation.
///

View File

@ -1,14 +1,17 @@
#![allow(
clippy::disallowed_names,
clippy::let_underscore_untyped,
clippy::shadow_unrelated,
clippy::unseparated_literal_suffix,
clippy::used_underscore_binding
)]
extern crate proc_macro;
use std::borrow::Cow;
use std::collections::BTreeSet;
use proc_macro2::{Ident, Span, TokenStream};
use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream};
use quote::{format_ident, quote, quote_spanned, TokenStreamExt};
struct X;
@ -517,3 +520,30 @@ fn test_quote_raw_id() {
let id = quote!(r#raw_id);
assert_eq!(id.to_string(), "r#raw_id");
}
#[test]
fn test_type_inference_for_span() {
trait CallSite {
fn get() -> Self;
}
impl CallSite for Span {
fn get() -> Self {
Span::call_site()
}
}
let span = Span::call_site();
let _ = quote_spanned!(span=> ...);
let delim_span = Group::new(Delimiter::Parenthesis, TokenStream::new()).delim_span();
let _ = quote_spanned!(delim_span=> ...);
let inferred = CallSite::get();
let _ = quote_spanned!(inferred=> ...);
if false {
let proc_macro_span = proc_macro::Span::call_site();
let _ = quote_spanned!(proc_macro_span.into()=> ...);
}
}

View File

@ -4,7 +4,8 @@ error[E0308]: mismatched types
8 | quote!(#(#nonrep #nonrep)*);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
| expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
| expected due to this
| here the type of `has_iter` is inferred to be `ThereIsNoIteratorInRepetition`
|
= note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -4,7 +4,8 @@ error[E0308]: mismatched types
8 | quote!(#(#nonrep)*);
| ^^^^^^^^^^^^^^^^^^^
| |
| expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
| expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
| expected due to this
| here the type of `has_iter` is inferred to be `ThereIsNoIteratorInRepetition`
|
= note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -4,7 +4,7 @@ error[E0308]: mismatched types
4 | quote!(#(a b),*);
| ^^^^^^^^^^^^^^^^
| |
| expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
| expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
| expected due to this
|
= note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -4,7 +4,7 @@ error[E0308]: mismatched types
4 | quote!(#(a b)*);
| ^^^^^^^^^^^^^^^
| |
| expected struct `HasIterator`, found struct `ThereIsNoIteratorInRepetition`
| expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
| expected due to this
|
= note: this error originates in the macro `$crate::quote_token_with_context` which comes from the expansion of the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -3,5 +3,5 @@ use std::net::Ipv4Addr;
fn main() {
let ip = Ipv4Addr::LOCALHOST;
_ = quote! { #ip };
let _ = quote! { #ip };
}

View File

@ -1,20 +1,20 @@
error[E0277]: the trait bound `Ipv4Addr: ToTokens` is not satisfied
--> tests/ui/not-quotable.rs:6:9
--> tests/ui/not-quotable.rs:6:13
|
6 | _ = quote! { #ip };
| ^^^^^^^^^^^^^^
| |
| the trait `ToTokens` is not implemented for `Ipv4Addr`
| required by a bound introduced by this call
6 | let _ = quote! { #ip };
| ^^^^^^^^^^^^^^
| |
| the trait `ToTokens` is not implemented for `Ipv4Addr`
| required by a bound introduced by this call
|
= help: the following other types implement trait `ToTokens`:
&'a T
&'a mut T
Box<T>
Cow<'a, T>
Option<T>
Rc<T>
RepInterp<T>
String
and 23 others
bool
char
isize
i8
i16
i32
i64
i128
and $N others
= note: this error originates in the macro `quote` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -4,5 +4,5 @@ struct Ipv4Addr;
fn main() {
let ip = Ipv4Addr;
_ = quote! { #(#ip)* };
let _ = quote! { #(#ip)* };
}

View File

@ -1,5 +1,5 @@
error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied
--> tests/ui/not-repeatable.rs:7:9
--> tests/ui/not-repeatable.rs:7:13
|
3 | struct Ipv4Addr;
| ---------------
@ -10,8 +10,8 @@ error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its
| doesn't satisfy `Ipv4Addr: ext::RepIteratorExt`
| doesn't satisfy `Ipv4Addr: ext::RepToTokensExt`
...
7 | _ = quote! { #(#ip)* };
| ^^^^^^^^^^^^^^^^^^ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds
7 | let _ = quote! { #(#ip)* };
| ^^^^^^^^^^^^^^^^^^ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`Ipv4Addr: Iterator`

View File

@ -1,8 +1,10 @@
error[E0308]: mismatched types
--> tests/ui/wrong-type-span.rs:6:20
--> tests/ui/wrong-type-span.rs:6:5
|
6 | quote_spanned!(span=> #x);
| ---------------^^^^------
| | |
| | expected struct `Span`, found `&str`
| ^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected `Span`, found `&str`
| expected due to this
|
= note: this error originates in the macro `quote_spanned` (in Nightly builds, run with -Z macro-backtrace for more info)