Auto merge of #61758 - Centril:rollup-ew2uxng, r=Centril
Rollup of 9 pull requests Successful merges: - #60187 (Generator optimization: Overlap locals that never have storage live at the same time) - #61348 (Implement Clone::clone_from for Option and Result) - #61568 (Use Symbol, Span in libfmt_macros) - #61632 (ci: Collect CPU usage statistics on Azure) - #61654 (use pattern matching for slices destructuring) - #61671 (implement nth_back for Range(Inclusive)) - #61688 (is_fp and is_floating_point do the same thing, remove the former) - #61705 (Pass cflags rather than cxxflags to LLVM as CMAKE_C_FLAGS) - #61734 (Migrate rust-by-example to MdBook2) Failed merges: r? @ghost
This commit is contained in:
commit
c4797fa4f4
|
@ -11,6 +11,12 @@ steps:
|
||||||
- checkout: self
|
- checkout: self
|
||||||
fetchDepth: 2
|
fetchDepth: 2
|
||||||
|
|
||||||
|
# Spawn a background process to collect CPU usage statistics which we'll upload
|
||||||
|
# at the end of the build. See the comments in the script here for more
|
||||||
|
# information.
|
||||||
|
- bash: python src/ci/cpu-usage-over-time.py &> cpu-usage.csv &
|
||||||
|
displayName: "Collect CPU-usage statistics in the background"
|
||||||
|
|
||||||
- bash: printenv | sort
|
- bash: printenv | sort
|
||||||
displayName: Show environment variables
|
displayName: Show environment variables
|
||||||
|
|
||||||
|
@ -142,3 +148,13 @@ steps:
|
||||||
AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY)
|
AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY)
|
||||||
condition: and(succeeded(), or(eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1')))
|
condition: and(succeeded(), or(eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1')))
|
||||||
displayName: Upload artifacts
|
displayName: Upload artifacts
|
||||||
|
|
||||||
|
# Upload CPU usage statistics that we've been gathering this whole time. Always
|
||||||
|
# execute this step in case we want to inspect failed builds, but don't let
|
||||||
|
# errors here ever fail the build since this is just informational.
|
||||||
|
- bash: aws s3 cp --acl public-read cpu-usage.csv s3://$DEPLOY_BUCKET/rustc-builds/$BUILD_SOURCEVERSION/cpu-$SYSTEM_JOBNAME.csv
|
||||||
|
env:
|
||||||
|
AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY)
|
||||||
|
condition: contains(variables, 'AWS_SECRET_ACCESS_KEY')
|
||||||
|
continueOnError: true
|
||||||
|
displayName: Upload CPU usage statistics
|
||||||
|
|
|
@ -910,6 +910,9 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fmt_macros"
|
name = "fmt_macros"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"syntax_pos 0.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
|
|
|
@ -64,7 +64,7 @@ book!(
|
||||||
EmbeddedBook, "src/doc/embedded-book", "embedded-book", RustbookVersion::MdBook2;
|
EmbeddedBook, "src/doc/embedded-book", "embedded-book", RustbookVersion::MdBook2;
|
||||||
Nomicon, "src/doc/nomicon", "nomicon", RustbookVersion::MdBook2;
|
Nomicon, "src/doc/nomicon", "nomicon", RustbookVersion::MdBook2;
|
||||||
Reference, "src/doc/reference", "reference", RustbookVersion::MdBook1;
|
Reference, "src/doc/reference", "reference", RustbookVersion::MdBook1;
|
||||||
RustByExample, "src/doc/rust-by-example", "rust-by-example", RustbookVersion::MdBook1;
|
RustByExample, "src/doc/rust-by-example", "rust-by-example", RustbookVersion::MdBook2;
|
||||||
RustcBook, "src/doc/rustc", "rustc", RustbookVersion::MdBook1;
|
RustcBook, "src/doc/rustc", "rustc", RustbookVersion::MdBook1;
|
||||||
RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::MdBook2;
|
RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::MdBook2;
|
||||||
);
|
);
|
||||||
|
|
|
@ -416,7 +416,7 @@ fn configure_cmake(builder: &Builder<'_>,
|
||||||
|
|
||||||
cfg.build_arg("-j").build_arg(builder.jobs().to_string());
|
cfg.build_arg("-j").build_arg(builder.jobs().to_string());
|
||||||
let mut cflags = builder.cflags(target, GitRepo::Llvm).join(" ");
|
let mut cflags = builder.cflags(target, GitRepo::Llvm).join(" ");
|
||||||
if let Some(ref s) = builder.config.llvm_cxxflags {
|
if let Some(ref s) = builder.config.llvm_cflags {
|
||||||
cflags.push_str(&format!(" {}", s));
|
cflags.push_str(&format!(" {}", s));
|
||||||
}
|
}
|
||||||
cfg.define("CMAKE_C_FLAGS", cflags);
|
cfg.define("CMAKE_C_FLAGS", cflags);
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# ignore-tidy-linelength
|
||||||
|
|
||||||
|
# This is a small script that we use on CI to collect CPU usage statistics of
|
||||||
|
# our builders. By seeing graphs of CPU usage over time we hope to correlate
|
||||||
|
# that with possible improvements to Rust's own build system, ideally diagnosing
|
||||||
|
# that either builders are always fully using their CPU resources or they're
|
||||||
|
# idle for long stretches of time.
|
||||||
|
#
|
||||||
|
# This script is relatively simple, but it's platform specific. Each platform
|
||||||
|
# (OSX/Windows/Linux) has a different way of calculating the current state of
|
||||||
|
# CPU at a point in time. We then compare two captured states to determine the
|
||||||
|
# percentage of time spent in one state versus another. The state capturing is
|
||||||
|
# all platform-specific but the loop at the bottom is the cross platform part
|
||||||
|
# that executes everywhere.
|
||||||
|
#
|
||||||
|
# # Viewing statistics
|
||||||
|
#
|
||||||
|
# All builders will upload their CPU statistics as CSV files to our S3 buckets.
|
||||||
|
# These URLS look like:
|
||||||
|
#
|
||||||
|
# https://$bucket.s3.amazonaws.com/rustc-builds/$commit/cpu-$builder.csv
|
||||||
|
#
|
||||||
|
# for example
|
||||||
|
#
|
||||||
|
# https://rust-lang-ci2.s3.amazonaws.com/rustc-builds/68baada19cd5340f05f0db15a3e16d6671609bcc/cpu-x86_64-apple.csv
|
||||||
|
#
|
||||||
|
# Each CSV file has two columns. The first is the timestamp of the measurement
|
||||||
|
# and the second column is the % of idle cpu time in that time slice. Ideally
|
||||||
|
# the second column is always zero.
|
||||||
|
#
|
||||||
|
# Once you've downloaded a file there's various ways to plot it and visualize
|
||||||
|
# it. For command line usage you can use a script like so:
|
||||||
|
#
|
||||||
|
# set timefmt '%Y-%m-%dT%H:%M:%S'
|
||||||
|
# set xdata time
|
||||||
|
# set ylabel "Idle CPU %"
|
||||||
|
# set xlabel "Time"
|
||||||
|
# set datafile sep ','
|
||||||
|
# set term png
|
||||||
|
# set output "printme.png"
|
||||||
|
# set grid
|
||||||
|
# builder = "i686-apple"
|
||||||
|
# plot "cpu-".builder.".csv" using 1:2 with lines title builder
|
||||||
|
#
|
||||||
|
# Executed as `gnuplot < ./foo.plot` it will generate a graph called
|
||||||
|
# `printme.png` which you can then open up. If you know how to improve this
|
||||||
|
# script or the viewing process that would be much appreciated :) (or even if
|
||||||
|
# you know how to automate it!)
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
if sys.platform == 'linux2':
|
||||||
|
class State:
|
||||||
|
def __init__(self):
|
||||||
|
with open('/proc/stat', 'r') as file:
|
||||||
|
data = file.readline().split()
|
||||||
|
if data[0] != 'cpu':
|
||||||
|
raise Exception('did not start with "cpu"')
|
||||||
|
self.user = int(data[1])
|
||||||
|
self.nice = int(data[2])
|
||||||
|
self.system = int(data[3])
|
||||||
|
self.idle = int(data[4])
|
||||||
|
self.iowait = int(data[5])
|
||||||
|
self.irq = int(data[6])
|
||||||
|
self.softirq = int(data[7])
|
||||||
|
self.steal = int(data[8])
|
||||||
|
self.guest = int(data[9])
|
||||||
|
self.guest_nice = int(data[10])
|
||||||
|
|
||||||
|
def idle_since(self, prev):
|
||||||
|
user = self.user - prev.user
|
||||||
|
nice = self.nice - prev.nice
|
||||||
|
system = self.system - prev.system
|
||||||
|
idle = self.idle - prev.idle
|
||||||
|
iowait = self.iowait - prev.iowait
|
||||||
|
irq = self.irq - prev.irq
|
||||||
|
softirq = self.softirq - prev.softirq
|
||||||
|
steal = self.steal - prev.steal
|
||||||
|
guest = self.guest - prev.guest
|
||||||
|
guest_nice = self.guest_nice - prev.guest_nice
|
||||||
|
total = user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice
|
||||||
|
return float(idle) / float(total) * 100
|
||||||
|
|
||||||
|
elif sys.platform == 'win32':
|
||||||
|
from ctypes.wintypes import DWORD
|
||||||
|
from ctypes import Structure, windll, WinError, GetLastError, byref
|
||||||
|
|
||||||
|
class FILETIME(Structure):
|
||||||
|
_fields_ = [
|
||||||
|
("dwLowDateTime", DWORD),
|
||||||
|
("dwHighDateTime", DWORD),
|
||||||
|
]
|
||||||
|
|
||||||
|
class State:
|
||||||
|
def __init__(self):
|
||||||
|
idle, kernel, user = FILETIME(), FILETIME(), FILETIME()
|
||||||
|
|
||||||
|
success = windll.kernel32.GetSystemTimes(
|
||||||
|
byref(idle),
|
||||||
|
byref(kernel),
|
||||||
|
byref(user),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert success, WinError(GetLastError())[1]
|
||||||
|
|
||||||
|
self.idle = (idle.dwHighDateTime << 32) | idle.dwLowDateTime
|
||||||
|
self.kernel = (kernel.dwHighDateTime << 32) | kernel.dwLowDateTime
|
||||||
|
self.user = (user.dwHighDateTime << 32) | user.dwLowDateTime
|
||||||
|
|
||||||
|
def idle_since(self, prev):
|
||||||
|
idle = self.idle - prev.idle
|
||||||
|
user = self.user - prev.user
|
||||||
|
kernel = self.kernel - prev.kernel
|
||||||
|
return float(idle) / float(user + kernel) * 100
|
||||||
|
|
||||||
|
elif sys.platform == 'darwin':
|
||||||
|
from ctypes import *
|
||||||
|
libc = cdll.LoadLibrary('/usr/lib/libc.dylib')
|
||||||
|
|
||||||
|
PROESSOR_CPU_LOAD_INFO = c_int(2)
|
||||||
|
CPU_STATE_USER = 0
|
||||||
|
CPU_STATE_SYSTEM = 1
|
||||||
|
CPU_STATE_IDLE = 2
|
||||||
|
CPU_STATE_NICE = 3
|
||||||
|
c_int_p = POINTER(c_int)
|
||||||
|
|
||||||
|
class State:
|
||||||
|
def __init__(self):
|
||||||
|
num_cpus_u = c_uint(0)
|
||||||
|
cpu_info = c_int_p()
|
||||||
|
cpu_info_cnt = c_int(0)
|
||||||
|
err = libc.host_processor_info(
|
||||||
|
libc.mach_host_self(),
|
||||||
|
PROESSOR_CPU_LOAD_INFO,
|
||||||
|
byref(num_cpus_u),
|
||||||
|
byref(cpu_info),
|
||||||
|
byref(cpu_info_cnt),
|
||||||
|
)
|
||||||
|
assert err == 0
|
||||||
|
self.user = 0
|
||||||
|
self.system = 0
|
||||||
|
self.idle = 0
|
||||||
|
self.nice = 0
|
||||||
|
cur = 0
|
||||||
|
while cur < cpu_info_cnt.value:
|
||||||
|
self.user += cpu_info[cur + CPU_STATE_USER]
|
||||||
|
self.system += cpu_info[cur + CPU_STATE_SYSTEM]
|
||||||
|
self.idle += cpu_info[cur + CPU_STATE_IDLE]
|
||||||
|
self.nice += cpu_info[cur + CPU_STATE_NICE]
|
||||||
|
cur += num_cpus_u.value
|
||||||
|
|
||||||
|
def idle_since(self, prev):
|
||||||
|
user = self.user - prev.user
|
||||||
|
system = self.system - prev.system
|
||||||
|
idle = self.idle - prev.idle
|
||||||
|
nice = self.nice - prev.nice
|
||||||
|
return float(idle) / float(user + system + idle + nice) * 100.0
|
||||||
|
|
||||||
|
else:
|
||||||
|
print('unknown platform', sys.platform)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
cur_state = State();
|
||||||
|
print("Time,Idle")
|
||||||
|
while True:
|
||||||
|
time.sleep(1);
|
||||||
|
next_state = State();
|
||||||
|
now = datetime.datetime.utcnow().isoformat()
|
||||||
|
idle = next_state.idle_since(cur_state)
|
||||||
|
print("%s,%s" % (now, idle))
|
||||||
|
sys.stdout.flush()
|
||||||
|
cur_state = next_state
|
|
@ -1 +1 @@
|
||||||
Subproject commit 18566f4dedc3ef5bf61f5f85685d5966db99cc11
|
Subproject commit d8eec1dd65470b9a68e80ac1cba8fad0daac4916
|
|
@ -281,6 +281,19 @@ impl<A: Step> DoubleEndedIterator for ops::Range<A> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn nth_back(&mut self, n: usize) -> Option<A> {
|
||||||
|
if let Some(minus_n) = self.end.sub_usize(n) {
|
||||||
|
if minus_n > self.start {
|
||||||
|
self.end = minus_n.sub_one();
|
||||||
|
return Some(self.end.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.end = self.start.clone();
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "fused", since = "1.26.0")]
|
#[stable(feature = "fused", since = "1.26.0")]
|
||||||
|
@ -438,6 +451,34 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn nth_back(&mut self, n: usize) -> Option<A> {
|
||||||
|
self.compute_is_empty();
|
||||||
|
if self.is_empty.unwrap_or_default() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(minus_n) = self.end.sub_usize(n) {
|
||||||
|
use crate::cmp::Ordering::*;
|
||||||
|
|
||||||
|
match minus_n.partial_cmp(&self.start) {
|
||||||
|
Some(Greater) => {
|
||||||
|
self.is_empty = Some(false);
|
||||||
|
self.end = minus_n.sub_one();
|
||||||
|
return Some(minus_n);
|
||||||
|
}
|
||||||
|
Some(Equal) => {
|
||||||
|
self.is_empty = Some(true);
|
||||||
|
return Some(minus_n);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.is_empty = Some(true);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
|
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
|
||||||
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
|
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
|
||||||
|
|
|
@ -145,7 +145,7 @@ use crate::pin::Pin;
|
||||||
// which basically means it must be `Option`.
|
// which basically means it must be `Option`.
|
||||||
|
|
||||||
/// The `Option` type. See [the module level documentation](index.html) for more.
|
/// The `Option` type. See [the module level documentation](index.html) for more.
|
||||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub enum Option<T> {
|
pub enum Option<T> {
|
||||||
/// No value
|
/// No value
|
||||||
|
@ -1040,6 +1040,25 @@ fn expect_failed(msg: &str) -> ! {
|
||||||
// Trait implementations
|
// Trait implementations
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<T: Clone> Clone for Option<T> {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Some(x) => Some(x.clone()),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clone_from(&mut self, source: &Self) {
|
||||||
|
match (self, source) {
|
||||||
|
(Some(to), Some(from)) => to.clone_from(from),
|
||||||
|
(to, from) => *to = from.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T> Default for Option<T> {
|
impl<T> Default for Option<T> {
|
||||||
/// Returns [`None`][Option::None].
|
/// Returns [`None`][Option::None].
|
||||||
|
|
|
@ -240,7 +240,7 @@ use crate::ops::{self, Deref};
|
||||||
///
|
///
|
||||||
/// [`Ok`]: enum.Result.html#variant.Ok
|
/// [`Ok`]: enum.Result.html#variant.Ok
|
||||||
/// [`Err`]: enum.Result.html#variant.Err
|
/// [`Err`]: enum.Result.html#variant.Err
|
||||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
||||||
#[must_use = "this `Result` may be an `Err` variant, which should be handled"]
|
#[must_use = "this `Result` may be an `Err` variant, which should be handled"]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub enum Result<T, E> {
|
pub enum Result<T, E> {
|
||||||
|
@ -1003,6 +1003,27 @@ fn unwrap_failed<E: fmt::Debug>(msg: &str, error: E) -> ! {
|
||||||
// Trait implementations
|
// Trait implementations
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<T: Clone, E: Clone> Clone for Result<T, E> {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Ok(x) => Ok(x.clone()),
|
||||||
|
Err(x) => Err(x.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn clone_from(&mut self, source: &Self) {
|
||||||
|
match (self, source) {
|
||||||
|
(Ok(to), Ok(from)) => to.clone_from(from),
|
||||||
|
(Err(to), Err(from)) => to.clone_from(from),
|
||||||
|
(to, from) => *to = from.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T, E> IntoIterator for Result<T, E> {
|
impl<T, E> IntoIterator for Result<T, E> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
|
@ -1657,6 +1657,23 @@ fn test_range_nth() {
|
||||||
assert_eq!(r, 20..20);
|
assert_eq!(r, 20..20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_range_nth_back() {
|
||||||
|
assert_eq!((10..15).nth_back(0), Some(14));
|
||||||
|
assert_eq!((10..15).nth_back(1), Some(13));
|
||||||
|
assert_eq!((10..15).nth_back(4), Some(10));
|
||||||
|
assert_eq!((10..15).nth_back(5), None);
|
||||||
|
assert_eq!((-120..80_i8).nth_back(199), Some(-120));
|
||||||
|
|
||||||
|
let mut r = 10..20;
|
||||||
|
assert_eq!(r.nth_back(2), Some(17));
|
||||||
|
assert_eq!(r, 10..17);
|
||||||
|
assert_eq!(r.nth_back(2), Some(14));
|
||||||
|
assert_eq!(r, 10..14);
|
||||||
|
assert_eq!(r.nth_back(10), None);
|
||||||
|
assert_eq!(r, 10..10);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_range_from_nth() {
|
fn test_range_from_nth() {
|
||||||
assert_eq!((10..).nth(0), Some(10));
|
assert_eq!((10..).nth(0), Some(10));
|
||||||
|
@ -1714,6 +1731,26 @@ fn test_range_inclusive_nth() {
|
||||||
assert_eq!(ExactSizeIterator::is_empty(&r), true);
|
assert_eq!(ExactSizeIterator::is_empty(&r), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_range_inclusive_nth_back() {
|
||||||
|
assert_eq!((10..=15).nth_back(0), Some(15));
|
||||||
|
assert_eq!((10..=15).nth_back(1), Some(14));
|
||||||
|
assert_eq!((10..=15).nth_back(5), Some(10));
|
||||||
|
assert_eq!((10..=15).nth_back(6), None);
|
||||||
|
assert_eq!((-120..=80_i8).nth_back(200), Some(-120));
|
||||||
|
|
||||||
|
let mut r = 10_u8..=20;
|
||||||
|
assert_eq!(r.nth_back(2), Some(18));
|
||||||
|
assert_eq!(r, 10..=17);
|
||||||
|
assert_eq!(r.nth_back(2), Some(15));
|
||||||
|
assert_eq!(r, 10..=14);
|
||||||
|
assert_eq!(r.is_empty(), false);
|
||||||
|
assert_eq!(ExactSizeIterator::is_empty(&r), false);
|
||||||
|
assert_eq!(r.nth_back(10), None);
|
||||||
|
assert_eq!(r.is_empty(), true);
|
||||||
|
assert_eq!(ExactSizeIterator::is_empty(&r), true);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_range_step() {
|
fn test_range_step() {
|
||||||
#![allow(deprecated)]
|
#![allow(deprecated)]
|
||||||
|
|
|
@ -8,3 +8,6 @@ edition = "2018"
|
||||||
name = "fmt_macros"
|
name = "fmt_macros"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
crate-type = ["dylib"]
|
crate-type = ["dylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syntax_pos = { path = "../libsyntax_pos" }
|
||||||
|
|
|
@ -25,6 +25,17 @@ use std::str;
|
||||||
use std::string;
|
use std::string;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
use syntax_pos::{InnerSpan, Symbol};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct InnerOffset(usize);
|
||||||
|
|
||||||
|
impl InnerOffset {
|
||||||
|
fn to(self, end: InnerOffset) -> InnerSpan {
|
||||||
|
InnerSpan::new(self.0, end.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A piece is a portion of the format string which represents the next part
|
/// A piece is a portion of the format string which represents the next part
|
||||||
/// to emit. These are emitted as a stream by the `Parser` class.
|
/// to emit. These are emitted as a stream by the `Parser` class.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
@ -40,7 +51,7 @@ pub enum Piece<'a> {
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct Argument<'a> {
|
pub struct Argument<'a> {
|
||||||
/// Where to find this argument
|
/// Where to find this argument
|
||||||
pub position: Position<'a>,
|
pub position: Position,
|
||||||
/// How to format the argument
|
/// How to format the argument
|
||||||
pub format: FormatSpec<'a>,
|
pub format: FormatSpec<'a>,
|
||||||
}
|
}
|
||||||
|
@ -55,9 +66,9 @@ pub struct FormatSpec<'a> {
|
||||||
/// Packed version of various flags provided
|
/// Packed version of various flags provided
|
||||||
pub flags: u32,
|
pub flags: u32,
|
||||||
/// The integer precision to use
|
/// The integer precision to use
|
||||||
pub precision: Count<'a>,
|
pub precision: Count,
|
||||||
/// The string width requested for the resulting format
|
/// The string width requested for the resulting format
|
||||||
pub width: Count<'a>,
|
pub width: Count,
|
||||||
/// The descriptor string representing the name of the format desired for
|
/// The descriptor string representing the name of the format desired for
|
||||||
/// this argument, this can be empty or any number of characters, although
|
/// this argument, this can be empty or any number of characters, although
|
||||||
/// it is required to be one word.
|
/// it is required to be one word.
|
||||||
|
@ -66,16 +77,16 @@ pub struct FormatSpec<'a> {
|
||||||
|
|
||||||
/// Enum describing where an argument for a format can be located.
|
/// Enum describing where an argument for a format can be located.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum Position<'a> {
|
pub enum Position {
|
||||||
/// The argument is implied to be located at an index
|
/// The argument is implied to be located at an index
|
||||||
ArgumentImplicitlyIs(usize),
|
ArgumentImplicitlyIs(usize),
|
||||||
/// The argument is located at a specific index given in the format
|
/// The argument is located at a specific index given in the format
|
||||||
ArgumentIs(usize),
|
ArgumentIs(usize),
|
||||||
/// The argument has a name.
|
/// The argument has a name.
|
||||||
ArgumentNamed(&'a str),
|
ArgumentNamed(Symbol),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Position<'_> {
|
impl Position {
|
||||||
pub fn index(&self) -> Option<usize> {
|
pub fn index(&self) -> Option<usize> {
|
||||||
match self {
|
match self {
|
||||||
ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
|
ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
|
||||||
|
@ -120,11 +131,11 @@ pub enum Flag {
|
||||||
/// A count is used for the precision and width parameters of an integer, and
|
/// A count is used for the precision and width parameters of an integer, and
|
||||||
/// can reference either an argument or a literal integer.
|
/// can reference either an argument or a literal integer.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum Count<'a> {
|
pub enum Count {
|
||||||
/// The count is specified explicitly.
|
/// The count is specified explicitly.
|
||||||
CountIs(usize),
|
CountIs(usize),
|
||||||
/// The count is specified by the argument with the given name.
|
/// The count is specified by the argument with the given name.
|
||||||
CountIsName(&'a str),
|
CountIsName(Symbol),
|
||||||
/// The count is specified by the argument at the given index.
|
/// The count is specified by the argument at the given index.
|
||||||
CountIsParam(usize),
|
CountIsParam(usize),
|
||||||
/// The count is implied and cannot be explicitly specified.
|
/// The count is implied and cannot be explicitly specified.
|
||||||
|
@ -135,9 +146,8 @@ pub struct ParseError {
|
||||||
pub description: string::String,
|
pub description: string::String,
|
||||||
pub note: Option<string::String>,
|
pub note: Option<string::String>,
|
||||||
pub label: string::String,
|
pub label: string::String,
|
||||||
pub start: SpanIndex,
|
pub span: InnerSpan,
|
||||||
pub end: SpanIndex,
|
pub secondary_label: Option<(string::String, InnerSpan)>,
|
||||||
pub secondary_label: Option<(string::String, SpanIndex, SpanIndex)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The parser structure for interpreting the input format string. This is
|
/// The parser structure for interpreting the input format string. This is
|
||||||
|
@ -156,24 +166,15 @@ pub struct Parser<'a> {
|
||||||
/// `Some(raw count)` when the string is "raw", used to position spans correctly
|
/// `Some(raw count)` when the string is "raw", used to position spans correctly
|
||||||
style: Option<usize>,
|
style: Option<usize>,
|
||||||
/// Start and end byte offset of every successfully parsed argument
|
/// Start and end byte offset of every successfully parsed argument
|
||||||
pub arg_places: Vec<(SpanIndex, SpanIndex)>,
|
pub arg_places: Vec<InnerSpan>,
|
||||||
/// Characters that need to be shifted
|
/// Characters that need to be shifted
|
||||||
skips: Vec<usize>,
|
skips: Vec<usize>,
|
||||||
/// Span offset of the last opening brace seen, used for error reporting
|
/// Span of the last opening brace seen, used for error reporting
|
||||||
last_opening_brace_pos: Option<SpanIndex>,
|
last_opening_brace: Option<InnerSpan>,
|
||||||
/// Wether the source string is comes from `println!` as opposed to `format!` or `print!`
|
/// Wether the source string is comes from `println!` as opposed to `format!` or `print!`
|
||||||
append_newline: bool,
|
append_newline: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct SpanIndex(pub usize);
|
|
||||||
|
|
||||||
impl SpanIndex {
|
|
||||||
pub fn unwrap(self) -> usize {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for Parser<'a> {
|
impl<'a> Iterator for Parser<'a> {
|
||||||
type Item = Piece<'a>;
|
type Item = Piece<'a>;
|
||||||
|
|
||||||
|
@ -181,19 +182,20 @@ impl<'a> Iterator for Parser<'a> {
|
||||||
if let Some(&(pos, c)) = self.cur.peek() {
|
if let Some(&(pos, c)) = self.cur.peek() {
|
||||||
match c {
|
match c {
|
||||||
'{' => {
|
'{' => {
|
||||||
let curr_last_brace = self.last_opening_brace_pos;
|
let curr_last_brace = self.last_opening_brace;
|
||||||
self.last_opening_brace_pos = Some(self.to_span_index(pos));
|
let byte_pos = self.to_span_index(pos);
|
||||||
|
self.last_opening_brace = Some(byte_pos.to(InnerOffset(byte_pos.0 + 1)));
|
||||||
self.cur.next();
|
self.cur.next();
|
||||||
if self.consume('{') {
|
if self.consume('{') {
|
||||||
self.last_opening_brace_pos = curr_last_brace;
|
self.last_opening_brace = curr_last_brace;
|
||||||
|
|
||||||
Some(String(self.string(pos + 1)))
|
Some(String(self.string(pos + 1)))
|
||||||
} else {
|
} else {
|
||||||
let arg = self.argument();
|
let arg = self.argument();
|
||||||
if let Some(arg_pos) = self.must_consume('}').map(|end| {
|
if let Some(end) = self.must_consume('}') {
|
||||||
(self.to_span_index(pos), self.to_span_index(end + 1))
|
let start = self.to_span_index(pos);
|
||||||
}) {
|
let end = self.to_span_index(end + 1);
|
||||||
self.arg_places.push(arg_pos);
|
self.arg_places.push(start.to(end));
|
||||||
}
|
}
|
||||||
Some(NextArgument(arg))
|
Some(NextArgument(arg))
|
||||||
}
|
}
|
||||||
|
@ -208,8 +210,7 @@ impl<'a> Iterator for Parser<'a> {
|
||||||
"unmatched `}` found",
|
"unmatched `}` found",
|
||||||
"unmatched `}`",
|
"unmatched `}`",
|
||||||
"if you intended to print `}`, you can escape it using `}}`",
|
"if you intended to print `}`, you can escape it using `}}`",
|
||||||
err_pos,
|
err_pos.to(err_pos),
|
||||||
err_pos,
|
|
||||||
);
|
);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -241,7 +242,7 @@ impl<'a> Parser<'a> {
|
||||||
style,
|
style,
|
||||||
arg_places: vec![],
|
arg_places: vec![],
|
||||||
skips,
|
skips,
|
||||||
last_opening_brace_pos: None,
|
last_opening_brace: None,
|
||||||
append_newline,
|
append_newline,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,15 +254,13 @@ impl<'a> Parser<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
description: S1,
|
description: S1,
|
||||||
label: S2,
|
label: S2,
|
||||||
start: SpanIndex,
|
span: InnerSpan,
|
||||||
end: SpanIndex,
|
|
||||||
) {
|
) {
|
||||||
self.errors.push(ParseError {
|
self.errors.push(ParseError {
|
||||||
description: description.into(),
|
description: description.into(),
|
||||||
note: None,
|
note: None,
|
||||||
label: label.into(),
|
label: label.into(),
|
||||||
start,
|
span,
|
||||||
end,
|
|
||||||
secondary_label: None,
|
secondary_label: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -274,15 +273,13 @@ impl<'a> Parser<'a> {
|
||||||
description: S1,
|
description: S1,
|
||||||
label: S2,
|
label: S2,
|
||||||
note: S3,
|
note: S3,
|
||||||
start: SpanIndex,
|
span: InnerSpan,
|
||||||
end: SpanIndex,
|
|
||||||
) {
|
) {
|
||||||
self.errors.push(ParseError {
|
self.errors.push(ParseError {
|
||||||
description: description.into(),
|
description: description.into(),
|
||||||
note: Some(note.into()),
|
note: Some(note.into()),
|
||||||
label: label.into(),
|
label: label.into(),
|
||||||
start,
|
span,
|
||||||
end,
|
|
||||||
secondary_label: None,
|
secondary_label: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -303,22 +300,21 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn raw(&self) -> usize {
|
fn to_span_index(&self, pos: usize) -> InnerOffset {
|
||||||
self.style.map(|raw| raw + 1).unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_span_index(&self, pos: usize) -> SpanIndex {
|
|
||||||
let mut pos = pos;
|
let mut pos = pos;
|
||||||
|
// This handles the raw string case, the raw argument is the number of #
|
||||||
|
// in r###"..."### (we need to add one because of the `r`).
|
||||||
|
let raw = self.style.map(|raw| raw + 1).unwrap_or(0);
|
||||||
for skip in &self.skips {
|
for skip in &self.skips {
|
||||||
if pos > *skip {
|
if pos > *skip {
|
||||||
pos += 1;
|
pos += 1;
|
||||||
} else if pos == *skip && self.raw() == 0 {
|
} else if pos == *skip && raw == 0 {
|
||||||
pos += 1;
|
pos += 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SpanIndex(self.raw() + pos + 1)
|
InnerOffset(raw + pos + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forces consumption of the specified character. If the character is not
|
/// Forces consumption of the specified character. If the character is not
|
||||||
|
@ -336,8 +332,8 @@ impl<'a> Parser<'a> {
|
||||||
let label = "expected `}`".to_owned();
|
let label = "expected `}`".to_owned();
|
||||||
let (note, secondary_label) = if c == '}' {
|
let (note, secondary_label) = if c == '}' {
|
||||||
(Some("if you intended to print `{`, you can escape it using `{{`".to_owned()),
|
(Some("if you intended to print `{`, you can escape it using `{{`".to_owned()),
|
||||||
self.last_opening_brace_pos.map(|pos| {
|
self.last_opening_brace.map(|sp| {
|
||||||
("because of this opening brace".to_owned(), pos, pos)
|
("because of this opening brace".to_owned(), sp)
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
(None, None)
|
(None, None)
|
||||||
|
@ -346,8 +342,7 @@ impl<'a> Parser<'a> {
|
||||||
description,
|
description,
|
||||||
note,
|
note,
|
||||||
label,
|
label,
|
||||||
start: pos,
|
span: pos.to(pos),
|
||||||
end: pos,
|
|
||||||
secondary_label,
|
secondary_label,
|
||||||
});
|
});
|
||||||
None
|
None
|
||||||
|
@ -361,8 +356,8 @@ impl<'a> Parser<'a> {
|
||||||
let label = format!("expected `{:?}`", c);
|
let label = format!("expected `{:?}`", c);
|
||||||
let (note, secondary_label) = if c == '}' {
|
let (note, secondary_label) = if c == '}' {
|
||||||
(Some("if you intended to print `{`, you can escape it using `{{`".to_owned()),
|
(Some("if you intended to print `{`, you can escape it using `{{`".to_owned()),
|
||||||
self.last_opening_brace_pos.map(|pos| {
|
self.last_opening_brace.map(|sp| {
|
||||||
("because of this opening brace".to_owned(), pos, pos)
|
("because of this opening brace".to_owned(), sp)
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
(None, None)
|
(None, None)
|
||||||
|
@ -371,12 +366,11 @@ impl<'a> Parser<'a> {
|
||||||
description,
|
description,
|
||||||
note,
|
note,
|
||||||
label,
|
label,
|
||||||
start: pos,
|
span: pos.to(pos),
|
||||||
end: pos,
|
|
||||||
secondary_label,
|
secondary_label,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
self.err(description, format!("expected `{:?}`", c), pos, pos);
|
self.err(description, format!("expected `{:?}`", c), pos.to(pos));
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -435,20 +429,24 @@ impl<'a> Parser<'a> {
|
||||||
/// integer index of an argument, a named argument, or a blank string.
|
/// integer index of an argument, a named argument, or a blank string.
|
||||||
/// Returns `Some(parsed_position)` if the position is not implicitly
|
/// Returns `Some(parsed_position)` if the position is not implicitly
|
||||||
/// consuming a macro argument, `None` if it's the case.
|
/// consuming a macro argument, `None` if it's the case.
|
||||||
fn position(&mut self) -> Option<Position<'a>> {
|
fn position(&mut self) -> Option<Position> {
|
||||||
if let Some(i) = self.integer() {
|
if let Some(i) = self.integer() {
|
||||||
Some(ArgumentIs(i))
|
Some(ArgumentIs(i))
|
||||||
} else {
|
} else {
|
||||||
match self.cur.peek() {
|
match self.cur.peek() {
|
||||||
Some(&(_, c)) if c.is_alphabetic() => Some(ArgumentNamed(self.word())),
|
Some(&(_, c)) if c.is_alphabetic() => {
|
||||||
|
Some(ArgumentNamed(Symbol::intern(self.word())))
|
||||||
|
}
|
||||||
Some(&(pos, c)) if c == '_' => {
|
Some(&(pos, c)) if c == '_' => {
|
||||||
let invalid_name = self.string(pos);
|
let invalid_name = self.string(pos);
|
||||||
self.err_with_note(format!("invalid argument name `{}`", invalid_name),
|
self.err_with_note(format!("invalid argument name `{}`", invalid_name),
|
||||||
"invalid argument name",
|
"invalid argument name",
|
||||||
"argument names cannot start with an underscore",
|
"argument names cannot start with an underscore",
|
||||||
self.to_span_index(pos),
|
self.to_span_index(pos).to(
|
||||||
self.to_span_index(pos + invalid_name.len()));
|
self.to_span_index(pos + invalid_name.len())
|
||||||
Some(ArgumentNamed(invalid_name))
|
),
|
||||||
|
);
|
||||||
|
Some(ArgumentNamed(Symbol::intern(invalid_name)))
|
||||||
},
|
},
|
||||||
|
|
||||||
// This is an `ArgumentNext`.
|
// This is an `ArgumentNext`.
|
||||||
|
@ -556,7 +554,7 @@ impl<'a> Parser<'a> {
|
||||||
/// Parses a Count parameter at the current position. This does not check
|
/// Parses a Count parameter at the current position. This does not check
|
||||||
/// for 'CountIsNextParam' because that is only used in precision, not
|
/// for 'CountIsNextParam' because that is only used in precision, not
|
||||||
/// width.
|
/// width.
|
||||||
fn count(&mut self) -> Count<'a> {
|
fn count(&mut self) -> Count {
|
||||||
if let Some(i) = self.integer() {
|
if let Some(i) = self.integer() {
|
||||||
if self.consume('$') {
|
if self.consume('$') {
|
||||||
CountIsParam(i)
|
CountIsParam(i)
|
||||||
|
@ -570,7 +568,7 @@ impl<'a> Parser<'a> {
|
||||||
self.cur = tmp;
|
self.cur = tmp;
|
||||||
CountImplied
|
CountImplied
|
||||||
} else if self.consume('$') {
|
} else if self.consume('$') {
|
||||||
CountIsName(word)
|
CountIsName(Symbol::intern(word))
|
||||||
} else {
|
} else {
|
||||||
self.cur = tmp;
|
self.cur = tmp;
|
||||||
CountImplied
|
CountImplied
|
||||||
|
@ -760,6 +758,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_counts() {
|
fn format_counts() {
|
||||||
|
use syntax_pos::{GLOBALS, Globals, edition};
|
||||||
|
GLOBALS.set(&Globals::new(edition::DEFAULT_EDITION), || {
|
||||||
same("{:10s}",
|
same("{:10s}",
|
||||||
&[NextArgument(Argument {
|
&[NextArgument(Argument {
|
||||||
position: ArgumentImplicitlyIs(0),
|
position: ArgumentImplicitlyIs(0),
|
||||||
|
@ -815,11 +815,12 @@ mod tests {
|
||||||
fill: None,
|
fill: None,
|
||||||
align: AlignUnknown,
|
align: AlignUnknown,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
precision: CountIsName("b"),
|
precision: CountIsName(Symbol::intern("b")),
|
||||||
width: CountIsName("a"),
|
width: CountIsName(Symbol::intern("a")),
|
||||||
ty: "s",
|
ty: "s",
|
||||||
},
|
},
|
||||||
})]);
|
})]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_flags() {
|
fn format_flags() {
|
||||||
|
|
|
@ -353,7 +353,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
_ => {
|
_ => {
|
||||||
// this is a "direct", user-specified, rather than derived,
|
// this is a "direct", user-specified, rather than derived,
|
||||||
// obligation.
|
// obligation.
|
||||||
flags.push(("direct".to_owned(), None));
|
flags.push((sym::direct, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,27 +365,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
// Currently I'm leaving it for what I need for `try`.
|
// Currently I'm leaving it for what I need for `try`.
|
||||||
if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
|
if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
|
||||||
let method = self.tcx.item_name(item);
|
let method = self.tcx.item_name(item);
|
||||||
flags.push(("from_method".to_owned(), None));
|
flags.push((sym::from_method, None));
|
||||||
flags.push(("from_method".to_owned(), Some(method.to_string())));
|
flags.push((sym::from_method, Some(method.to_string())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) {
|
if let Some(t) = self.get_parent_trait_ref(&obligation.cause.code) {
|
||||||
flags.push(("parent_trait".to_owned(), Some(t)));
|
flags.push((sym::parent_trait, Some(t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
|
if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
|
||||||
flags.push(("from_desugaring".to_owned(), None));
|
flags.push((sym::from_desugaring, None));
|
||||||
flags.push(("from_desugaring".to_owned(), Some(k.name().to_string())));
|
flags.push((sym::from_desugaring, Some(k.name().to_string())));
|
||||||
}
|
}
|
||||||
let generics = self.tcx.generics_of(def_id);
|
let generics = self.tcx.generics_of(def_id);
|
||||||
let self_ty = trait_ref.self_ty();
|
let self_ty = trait_ref.self_ty();
|
||||||
// This is also included through the generics list as `Self`,
|
// This is also included through the generics list as `Self`,
|
||||||
// but the parser won't allow you to use it
|
// but the parser won't allow you to use it
|
||||||
flags.push(("_Self".to_owned(), Some(self_ty.to_string())));
|
flags.push((sym::_Self, Some(self_ty.to_string())));
|
||||||
if let Some(def) = self_ty.ty_adt_def() {
|
if let Some(def) = self_ty.ty_adt_def() {
|
||||||
// We also want to be able to select self's original
|
// We also want to be able to select self's original
|
||||||
// signature with no type arguments resolved
|
// signature with no type arguments resolved
|
||||||
flags.push(("_Self".to_owned(), Some(self.tcx.type_of(def.did).to_string())));
|
flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string())));
|
||||||
}
|
}
|
||||||
|
|
||||||
for param in generics.params.iter() {
|
for param in generics.params.iter() {
|
||||||
|
@ -396,38 +396,38 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||||
},
|
},
|
||||||
GenericParamDefKind::Lifetime => continue,
|
GenericParamDefKind::Lifetime => continue,
|
||||||
};
|
};
|
||||||
let name = param.name.to_string();
|
let name = param.name.as_symbol();
|
||||||
flags.push((name, Some(value)));
|
flags.push((name, Some(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
|
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
|
||||||
flags.push(("crate_local".to_owned(), None));
|
flags.push((sym::crate_local, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow targeting all integers using `{integral}`, even if the exact type was resolved
|
// Allow targeting all integers using `{integral}`, even if the exact type was resolved
|
||||||
if self_ty.is_integral() {
|
if self_ty.is_integral() {
|
||||||
flags.push(("_Self".to_owned(), Some("{integral}".to_owned())));
|
flags.push((sym::_Self, Some("{integral}".to_owned())));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ty::Array(aty, len) = self_ty.sty {
|
if let ty::Array(aty, len) = self_ty.sty {
|
||||||
flags.push(("_Self".to_owned(), Some("[]".to_owned())));
|
flags.push((sym::_Self, Some("[]".to_owned())));
|
||||||
flags.push(("_Self".to_owned(), Some(format!("[{}]", aty))));
|
flags.push((sym::_Self, Some(format!("[{}]", aty))));
|
||||||
if let Some(def) = aty.ty_adt_def() {
|
if let Some(def) = aty.ty_adt_def() {
|
||||||
// We also want to be able to select the array's type's original
|
// We also want to be able to select the array's type's original
|
||||||
// signature with no type arguments resolved
|
// signature with no type arguments resolved
|
||||||
flags.push((
|
flags.push((
|
||||||
"_Self".to_owned(),
|
sym::_Self,
|
||||||
Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
|
Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
|
||||||
));
|
));
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
if let Some(len) = len.assert_usize(tcx) {
|
if let Some(len) = len.assert_usize(tcx) {
|
||||||
flags.push((
|
flags.push((
|
||||||
"_Self".to_owned(),
|
sym::_Self,
|
||||||
Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
|
Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
flags.push((
|
flags.push((
|
||||||
"_Self".to_owned(),
|
sym::_Self,
|
||||||
Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
|
Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::util::nodemap::FxHashMap;
|
||||||
|
|
||||||
use syntax::ast::{MetaItem, NestedMetaItem};
|
use syntax::ast::{MetaItem, NestedMetaItem};
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::symbol::sym;
|
use syntax::symbol::{Symbol, kw, sym};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
use syntax_pos::symbol::LocalInternedString;
|
use syntax_pos::symbol::LocalInternedString;
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ fn parse_error(tcx: TyCtxt<'_, '_, '_>, span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||||
pub fn parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
fn parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
items: &[NestedMetaItem],
|
items: &[NestedMetaItem],
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -167,7 +167,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||||
pub fn evaluate(&self,
|
pub fn evaluate(&self,
|
||||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
options: &[(String, Option<String>)])
|
options: &[(Symbol, Option<String>)])
|
||||||
-> OnUnimplementedNote
|
-> OnUnimplementedNote
|
||||||
{
|
{
|
||||||
let mut message = None;
|
let mut message = None;
|
||||||
|
@ -180,7 +180,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||||
if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
|
if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
|
||||||
c.ident().map_or(false, |ident| {
|
c.ident().map_or(false, |ident| {
|
||||||
options.contains(&(
|
options.contains(&(
|
||||||
ident.to_string(),
|
ident.name,
|
||||||
c.value_str().map(|s| s.as_str().to_string())
|
c.value_str().map(|s| s.as_str().to_string())
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
@ -203,8 +203,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let options: FxHashMap<String, String> = options.into_iter()
|
let options: FxHashMap<Symbol, String> = options.into_iter()
|
||||||
.filter_map(|(k, v)| v.as_ref().map(|v| (k.to_owned(), v.to_owned())))
|
.filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned())))
|
||||||
.collect();
|
.collect();
|
||||||
OnUnimplementedNote {
|
OnUnimplementedNote {
|
||||||
label: label.map(|l| l.format(tcx, trait_ref, &options)),
|
label: label.map(|l| l.format(tcx, trait_ref, &options)),
|
||||||
|
@ -215,7 +215,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
|
impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
|
||||||
pub fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
from: LocalInternedString,
|
from: LocalInternedString,
|
||||||
err_sp: Span)
|
err_sp: Span)
|
||||||
|
@ -241,16 +241,16 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
|
||||||
Piece::String(_) => (), // Normal string, no need to check it
|
Piece::String(_) => (), // Normal string, no need to check it
|
||||||
Piece::NextArgument(a) => match a.position {
|
Piece::NextArgument(a) => match a.position {
|
||||||
// `{Self}` is allowed
|
// `{Self}` is allowed
|
||||||
Position::ArgumentNamed(s) if s == "Self" => (),
|
Position::ArgumentNamed(s) if s == kw::SelfUpper => (),
|
||||||
// `{ThisTraitsName}` is allowed
|
// `{ThisTraitsName}` is allowed
|
||||||
Position::ArgumentNamed(s) if s == name.as_str() => (),
|
Position::ArgumentNamed(s) if s == name => (),
|
||||||
// `{from_method}` is allowed
|
// `{from_method}` is allowed
|
||||||
Position::ArgumentNamed(s) if s == "from_method" => (),
|
Position::ArgumentNamed(s) if s == sym::from_method => (),
|
||||||
// `{from_desugaring}` is allowed
|
// `{from_desugaring}` is allowed
|
||||||
Position::ArgumentNamed(s) if s == "from_desugaring" => (),
|
Position::ArgumentNamed(s) if s == sym::from_desugaring => (),
|
||||||
// So is `{A}` if A is a type parameter
|
// So is `{A}` if A is a type parameter
|
||||||
Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
|
Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
|
||||||
param.name.as_str() == s
|
param.name.as_symbol() == s
|
||||||
}) {
|
}) {
|
||||||
Some(_) => (),
|
Some(_) => (),
|
||||||
None => {
|
None => {
|
||||||
|
@ -276,7 +276,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
trait_ref: ty::TraitRef<'tcx>,
|
trait_ref: ty::TraitRef<'tcx>,
|
||||||
options: &FxHashMap<String, String>,
|
options: &FxHashMap<Symbol, String>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let name = tcx.item_name(trait_ref.def_id);
|
let name = tcx.item_name(trait_ref.def_id);
|
||||||
let trait_str = tcx.def_path_str(trait_ref.def_id);
|
let trait_str = tcx.def_path_str(trait_ref.def_id);
|
||||||
|
@ -289,9 +289,9 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
|
||||||
},
|
},
|
||||||
GenericParamDefKind::Lifetime => return None
|
GenericParamDefKind::Lifetime => return None
|
||||||
};
|
};
|
||||||
let name = param.name.to_string();
|
let name = param.name.as_symbol();
|
||||||
Some((name, value))
|
Some((name, value))
|
||||||
}).collect::<FxHashMap<String, String>>();
|
}).collect::<FxHashMap<Symbol, String>>();
|
||||||
let empty_string = String::new();
|
let empty_string = String::new();
|
||||||
|
|
||||||
let parser = Parser::new(&self.0, None, vec![], false);
|
let parser = Parser::new(&self.0, None, vec![], false);
|
||||||
|
@ -299,15 +299,15 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
|
||||||
match p {
|
match p {
|
||||||
Piece::String(s) => s,
|
Piece::String(s) => s,
|
||||||
Piece::NextArgument(a) => match a.position {
|
Piece::NextArgument(a) => match a.position {
|
||||||
Position::ArgumentNamed(s) => match generic_map.get(s) {
|
Position::ArgumentNamed(s) => match generic_map.get(&s) {
|
||||||
Some(val) => val,
|
Some(val) => val,
|
||||||
None if s == name.as_str() => {
|
None if s == name => {
|
||||||
&trait_str
|
&trait_str
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
if let Some(val) = options.get(s) {
|
if let Some(val) = options.get(&s) {
|
||||||
val
|
val
|
||||||
} else if s == "from_desugaring" || s == "from_method" {
|
} else if s == sym::from_desugaring || s == sym::from_method {
|
||||||
// don't break messages using these two arguments incorrectly
|
// don't break messages using these two arguments incorrectly
|
||||||
&empty_string
|
&empty_string
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1665,6 +1665,7 @@ impl RegionKind {
|
||||||
|
|
||||||
/// Type utilities
|
/// Type utilities
|
||||||
impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
|
#[inline]
|
||||||
pub fn is_unit(&self) -> bool {
|
pub fn is_unit(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Tuple(ref tys) => tys.is_empty(),
|
Tuple(ref tys) => tys.is_empty(),
|
||||||
|
@ -1672,6 +1673,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_never(&self) -> bool {
|
pub fn is_never(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Never => true,
|
Never => true,
|
||||||
|
@ -1726,6 +1728,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_primitive(&self) -> bool {
|
pub fn is_primitive(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Bool | Char | Int(_) | Uint(_) | Float(_) => true,
|
Bool | Char | Int(_) | Uint(_) | Float(_) => true,
|
||||||
|
@ -1741,6 +1744,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_ty_infer(&self) -> bool {
|
pub fn is_ty_infer(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Infer(_) => true,
|
Infer(_) => true,
|
||||||
|
@ -1748,6 +1752,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_phantom_data(&self) -> bool {
|
pub fn is_phantom_data(&self) -> bool {
|
||||||
if let Adt(def, _) = self.sty {
|
if let Adt(def, _) = self.sty {
|
||||||
def.is_phantom_data()
|
def.is_phantom_data()
|
||||||
|
@ -1756,8 +1761,10 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_bool(&self) -> bool { self.sty == Bool }
|
pub fn is_bool(&self) -> bool { self.sty == Bool }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_param(&self, index: u32) -> bool {
|
pub fn is_param(&self, index: u32) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
ty::Param(ref data) => data.index == index,
|
ty::Param(ref data) => data.index == index,
|
||||||
|
@ -1765,6 +1772,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_self(&self) -> bool {
|
pub fn is_self(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Param(ref p) => p.is_self(),
|
Param(ref p) => p.is_self(),
|
||||||
|
@ -1772,6 +1780,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_slice(&self) -> bool {
|
pub fn is_slice(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.sty {
|
RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.sty {
|
||||||
|
@ -1814,6 +1823,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_region_ptr(&self) -> bool {
|
pub fn is_region_ptr(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Ref(..) => true,
|
Ref(..) => true,
|
||||||
|
@ -1821,6 +1831,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_mutable_pointer(&self) -> bool {
|
pub fn is_mutable_pointer(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
RawPtr(TypeAndMut { mutbl: hir::Mutability::MutMutable, .. }) |
|
RawPtr(TypeAndMut { mutbl: hir::Mutability::MutMutable, .. }) |
|
||||||
|
@ -1829,6 +1840,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_unsafe_ptr(&self) -> bool {
|
pub fn is_unsafe_ptr(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
RawPtr(_) => return true,
|
RawPtr(_) => return true,
|
||||||
|
@ -1837,6 +1849,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if this type is an `Arc<T>`.
|
/// Returns `true` if this type is an `Arc<T>`.
|
||||||
|
#[inline]
|
||||||
pub fn is_arc(&self) -> bool {
|
pub fn is_arc(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Adt(def, _) => def.is_arc(),
|
Adt(def, _) => def.is_arc(),
|
||||||
|
@ -1845,6 +1858,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if this type is an `Rc<T>`.
|
/// Returns `true` if this type is an `Rc<T>`.
|
||||||
|
#[inline]
|
||||||
pub fn is_rc(&self) -> bool {
|
pub fn is_rc(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Adt(def, _) => def.is_rc(),
|
Adt(def, _) => def.is_rc(),
|
||||||
|
@ -1852,6 +1866,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_box(&self) -> bool {
|
pub fn is_box(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Adt(def, _) => def.is_box(),
|
Adt(def, _) => def.is_box(),
|
||||||
|
@ -1870,6 +1885,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
/// A scalar type is one that denotes an atomic datum, with no sub-components.
|
/// A scalar type is one that denotes an atomic datum, with no sub-components.
|
||||||
/// (A RawPtr is scalar because it represents a non-managed pointer, so its
|
/// (A RawPtr is scalar because it represents a non-managed pointer, so its
|
||||||
/// contents are abstract to rustc.)
|
/// contents are abstract to rustc.)
|
||||||
|
#[inline]
|
||||||
pub fn is_scalar(&self) -> bool {
|
pub fn is_scalar(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Bool | Char | Int(_) | Float(_) | Uint(_) |
|
Bool | Char | Int(_) | Float(_) | Uint(_) |
|
||||||
|
@ -1880,6 +1896,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if this type is a floating point type.
|
/// Returns `true` if this type is a floating point type.
|
||||||
|
#[inline]
|
||||||
pub fn is_floating_point(&self) -> bool {
|
pub fn is_floating_point(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Float(_) |
|
Float(_) |
|
||||||
|
@ -1888,6 +1905,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_trait(&self) -> bool {
|
pub fn is_trait(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Dynamic(..) => true,
|
Dynamic(..) => true,
|
||||||
|
@ -1895,6 +1913,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_enum(&self) -> bool {
|
pub fn is_enum(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Adt(adt_def, _) => {
|
Adt(adt_def, _) => {
|
||||||
|
@ -1904,6 +1923,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_closure(&self) -> bool {
|
pub fn is_closure(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Closure(..) => true,
|
Closure(..) => true,
|
||||||
|
@ -1911,6 +1931,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_generator(&self) -> bool {
|
pub fn is_generator(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Generator(..) => true,
|
Generator(..) => true,
|
||||||
|
@ -1926,6 +1947,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_fresh_ty(&self) -> bool {
|
pub fn is_fresh_ty(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Infer(FreshTy(_)) => true,
|
Infer(FreshTy(_)) => true,
|
||||||
|
@ -1933,6 +1955,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_fresh(&self) -> bool {
|
pub fn is_fresh(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Infer(FreshTy(_)) => true,
|
Infer(FreshTy(_)) => true,
|
||||||
|
@ -1942,6 +1965,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_char(&self) -> bool {
|
pub fn is_char(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Char => true,
|
Char => true,
|
||||||
|
@ -1950,17 +1974,11 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_fp(&self) -> bool {
|
|
||||||
match self.sty {
|
|
||||||
Infer(FloatVar(_)) | Float(_) => true,
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_numeric(&self) -> bool {
|
pub fn is_numeric(&self) -> bool {
|
||||||
self.is_integral() || self.is_fp()
|
self.is_integral() || self.is_floating_point()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_signed(&self) -> bool {
|
pub fn is_signed(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Int(_) => true,
|
Int(_) => true,
|
||||||
|
@ -1968,6 +1986,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_pointer_sized(&self) -> bool {
|
pub fn is_pointer_sized(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true,
|
Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true,
|
||||||
|
@ -1975,6 +1994,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_machine(&self) -> bool {
|
pub fn is_machine(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Int(..) | Uint(..) | Float(..) => true,
|
Int(..) | Uint(..) | Float(..) => true,
|
||||||
|
@ -1982,6 +2002,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn has_concrete_skeleton(&self) -> bool {
|
pub fn has_concrete_skeleton(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Param(_) | Infer(_) | Error => false,
|
Param(_) | Infer(_) | Error => false,
|
||||||
|
@ -2028,6 +2049,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_fn(&self) -> bool {
|
pub fn is_fn(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
FnDef(..) | FnPtr(_) => true,
|
FnDef(..) | FnPtr(_) => true,
|
||||||
|
@ -2043,6 +2065,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_impl_trait(&self) -> bool {
|
pub fn is_impl_trait(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
Opaque(..) => true,
|
Opaque(..) => true,
|
||||||
|
|
|
@ -429,7 +429,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
mir::Rvalue::UnaryOp(op, ref operand) => {
|
mir::Rvalue::UnaryOp(op, ref operand) => {
|
||||||
let operand = self.codegen_operand(&mut bx, operand);
|
let operand = self.codegen_operand(&mut bx, operand);
|
||||||
let lloperand = operand.immediate();
|
let lloperand = operand.immediate();
|
||||||
let is_float = operand.layout.ty.is_fp();
|
let is_float = operand.layout.ty.is_floating_point();
|
||||||
let llval = match op {
|
let llval = match op {
|
||||||
mir::UnOp::Not => bx.not(lloperand),
|
mir::UnOp::Not => bx.not(lloperand),
|
||||||
mir::UnOp::Neg => if is_float {
|
mir::UnOp::Neg => if is_float {
|
||||||
|
@ -536,7 +536,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
rhs: Bx::Value,
|
rhs: Bx::Value,
|
||||||
input_ty: Ty<'tcx>,
|
input_ty: Ty<'tcx>,
|
||||||
) -> Bx::Value {
|
) -> Bx::Value {
|
||||||
let is_float = input_ty.is_fp();
|
let is_float = input_ty.is_floating_point();
|
||||||
let is_signed = input_ty.is_signed();
|
let is_signed = input_ty.is_signed();
|
||||||
let is_unit = input_ty.is_unit();
|
let is_unit = input_ty.is_unit();
|
||||||
match op {
|
match op {
|
||||||
|
|
|
@ -4094,7 +4094,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
hir::UnNeg => {
|
hir::UnNeg => {
|
||||||
let result = self.check_user_unop(expr, oprnd_t, unop);
|
let result = self.check_user_unop(expr, oprnd_t, unop);
|
||||||
// If it's builtin, we can reuse the type, this helps inference.
|
// If it's builtin, we can reuse the type, this helps inference.
|
||||||
if !(oprnd_t.is_integral() || oprnd_t.is_fp()) {
|
if !oprnd_t.is_numeric() {
|
||||||
oprnd_t = result;
|
oprnd_t = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use errors::Applicability;
|
||||||
use syntax::parse::lexer::{StringReader as Lexer};
|
use syntax::parse::lexer::{StringReader as Lexer};
|
||||||
use syntax::parse::{ParseSess, token};
|
use syntax::parse::{ParseSess, token};
|
||||||
use syntax::source_map::FilePathMapping;
|
use syntax::source_map::FilePathMapping;
|
||||||
use syntax_pos::FileName;
|
use syntax_pos::{InnerSpan, FileName};
|
||||||
|
|
||||||
use crate::clean;
|
use crate::clean;
|
||||||
use crate::core::DocContext;
|
use crate::core::DocContext;
|
||||||
|
@ -63,7 +63,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if code_block.syntax.is_none() && code_block.is_fenced {
|
if code_block.syntax.is_none() && code_block.is_fenced {
|
||||||
let sp = sp.from_inner_byte_pos(0, 3);
|
let sp = sp.from_inner(InnerSpan::new(0, 3));
|
||||||
diag.span_suggestion(
|
diag.span_suggestion(
|
||||||
sp,
|
sp,
|
||||||
"mark blocks that do not contain Rust code as text",
|
"mark blocks that do not contain Rust code as text",
|
||||||
|
|
|
@ -6,7 +6,7 @@ use rustc::lint as lint;
|
||||||
use rustc::middle::privacy::AccessLevels;
|
use rustc::middle::privacy::AccessLevels;
|
||||||
use rustc::util::nodemap::DefIdSet;
|
use rustc::util::nodemap::DefIdSet;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use syntax_pos::{DUMMY_SP, Span};
|
use syntax_pos::{DUMMY_SP, InnerSpan, Span};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::clean::{self, GetDefId, Item};
|
use crate::clean::{self, GetDefId, Item};
|
||||||
|
@ -440,10 +440,10 @@ crate fn source_span_for_markdown_range(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let sp = span_of_attrs(attrs).from_inner_byte_pos(
|
let sp = span_of_attrs(attrs).from_inner(InnerSpan::new(
|
||||||
md_range.start + start_bytes,
|
md_range.start + start_bytes,
|
||||||
md_range.end + start_bytes + end_bytes,
|
md_range.end + start_bytes + end_bytes,
|
||||||
);
|
));
|
||||||
|
|
||||||
Some(sp)
|
Some(sp)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,10 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
token_tree: &[TokenTree])
|
token_tree: &[TokenTree])
|
||||||
-> Box<dyn MacResult+'cx> {
|
-> Box<dyn MacResult+'cx> {
|
||||||
let code = match (token_tree.len(), token_tree.get(0)) {
|
let code = match token_tree {
|
||||||
(1, Some(&TokenTree::Token(Token { kind: token::Ident(code, _), .. }))) => code,
|
[
|
||||||
|
TokenTree::Token(Token { kind: token::Ident(code, _), .. })
|
||||||
|
] => code,
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,22 +68,19 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
token_tree: &[TokenTree])
|
token_tree: &[TokenTree])
|
||||||
-> Box<dyn MacResult+'cx> {
|
-> Box<dyn MacResult+'cx> {
|
||||||
let (code, description) = match (
|
let (code, description) = match token_tree {
|
||||||
token_tree.len(),
|
[
|
||||||
token_tree.get(0),
|
TokenTree::Token(Token { kind: token::Ident(code, _), .. })
|
||||||
token_tree.get(1),
|
] => {
|
||||||
token_tree.get(2)
|
(*code, None)
|
||||||
) {
|
},
|
||||||
(1, Some(&TokenTree::Token(Token { kind: token::Ident(code, _), .. })), None, None) => {
|
[
|
||||||
(code, None)
|
TokenTree::Token(Token { kind: token::Ident(code, _), .. }),
|
||||||
|
TokenTree::Token(Token { kind: token::Comma, .. }),
|
||||||
|
TokenTree::Token(Token { kind: token::Literal(token::Lit { symbol, .. }), ..})
|
||||||
|
] => {
|
||||||
|
(*code, Some(*symbol))
|
||||||
},
|
},
|
||||||
(3, Some(&TokenTree::Token(Token { kind: token::Ident(code, _), .. })),
|
|
||||||
Some(&TokenTree::Token(Token { kind: token::Comma, .. })),
|
|
||||||
Some(&TokenTree::Token(Token {
|
|
||||||
kind: token::Literal(token::Lit { symbol, .. }), ..
|
|
||||||
}))) => {
|
|
||||||
(code, Some(symbol))
|
|
||||||
}
|
|
||||||
_ => unreachable!()
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -424,48 +424,38 @@ mod tests {
|
||||||
string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect();
|
string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect();
|
||||||
let tts: &[TokenTree] = &tts[..];
|
let tts: &[TokenTree] = &tts[..];
|
||||||
|
|
||||||
match (tts.len(), tts.get(0), tts.get(1), tts.get(2), tts.get(3)) {
|
match tts {
|
||||||
(
|
[
|
||||||
4,
|
TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }),
|
||||||
Some(&TokenTree::Token(Token {
|
TokenTree::Token(Token { kind: token::Not, .. }),
|
||||||
kind: token::Ident(name_macro_rules, false), ..
|
TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }),
|
||||||
})),
|
TokenTree::Delimited(_, macro_delim, macro_tts)
|
||||||
Some(&TokenTree::Token(Token { kind: token::Not, .. })),
|
]
|
||||||
Some(&TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. })),
|
if name_macro_rules == &sym::macro_rules && name_zip.as_str() == "zip" => {
|
||||||
Some(&TokenTree::Delimited(_, macro_delim, ref macro_tts)),
|
|
||||||
)
|
|
||||||
if name_macro_rules == sym::macro_rules && name_zip.as_str() == "zip" => {
|
|
||||||
let tts = ¯o_tts.trees().collect::<Vec<_>>();
|
let tts = ¯o_tts.trees().collect::<Vec<_>>();
|
||||||
match (tts.len(), tts.get(0), tts.get(1), tts.get(2)) {
|
match &tts[..] {
|
||||||
(
|
[
|
||||||
3,
|
TokenTree::Delimited(_, first_delim, first_tts),
|
||||||
Some(&TokenTree::Delimited(_, first_delim, ref first_tts)),
|
TokenTree::Token(Token { kind: token::FatArrow, .. }),
|
||||||
Some(&TokenTree::Token(Token { kind: token::FatArrow, .. })),
|
TokenTree::Delimited(_, second_delim, second_tts),
|
||||||
Some(&TokenTree::Delimited(_, second_delim, ref second_tts)),
|
]
|
||||||
)
|
if macro_delim == &token::Paren => {
|
||||||
if macro_delim == token::Paren => {
|
|
||||||
let tts = &first_tts.trees().collect::<Vec<_>>();
|
let tts = &first_tts.trees().collect::<Vec<_>>();
|
||||||
match (tts.len(), tts.get(0), tts.get(1)) {
|
match &tts[..] {
|
||||||
(
|
[
|
||||||
2,
|
TokenTree::Token(Token { kind: token::Dollar, .. }),
|
||||||
Some(&TokenTree::Token(Token { kind: token::Dollar, .. })),
|
TokenTree::Token(Token { kind: token::Ident(name, false), .. }),
|
||||||
Some(&TokenTree::Token(Token {
|
]
|
||||||
kind: token::Ident(name, false), ..
|
if first_delim == &token::Paren && name.as_str() == "a" => {},
|
||||||
})),
|
|
||||||
)
|
|
||||||
if first_delim == token::Paren && name.as_str() == "a" => {},
|
|
||||||
_ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
|
_ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
|
||||||
}
|
}
|
||||||
let tts = &second_tts.trees().collect::<Vec<_>>();
|
let tts = &second_tts.trees().collect::<Vec<_>>();
|
||||||
match (tts.len(), tts.get(0), tts.get(1)) {
|
match &tts[..] {
|
||||||
(
|
[
|
||||||
2,
|
TokenTree::Token(Token { kind: token::Dollar, .. }),
|
||||||
Some(&TokenTree::Token(Token { kind: token::Dollar, .. })),
|
TokenTree::Token(Token { kind: token::Ident(name, false), .. }),
|
||||||
Some(&TokenTree::Token(Token {
|
]
|
||||||
kind: token::Ident(name, false), ..
|
if second_delim == &token::Paren && name.as_str() == "a" => {},
|
||||||
})),
|
|
||||||
)
|
|
||||||
if second_delim == token::Paren && name.as_str() == "a" => {},
|
|
||||||
_ => panic!("value 4: {:?} {:?}", second_delim, second_tts),
|
_ => panic!("value 4: {:?} {:?}", second_delim, second_tts),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -82,8 +82,8 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let new = {
|
let new = {
|
||||||
let other_f = match (other_fs.len(), other_fs.get(0)) {
|
let other_f = match other_fs {
|
||||||
(1, Some(o_f)) => o_f,
|
[o_f] => o_f,
|
||||||
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"),
|
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt<'_>,
|
||||||
-> P<Expr>
|
-> P<Expr>
|
||||||
{
|
{
|
||||||
let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P<Expr>, other_fs: &[P<Expr>]| {
|
let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P<Expr>, other_fs: &[P<Expr>]| {
|
||||||
let other_f = match (other_fs.len(), other_fs.get(0)) {
|
let other_f = match other_fs {
|
||||||
(1, Some(o_f)) => o_f,
|
[o_f] => o_f,
|
||||||
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"),
|
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -143,8 +143,8 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let new = {
|
let new = {
|
||||||
let other_f = match (other_fs.len(), other_fs.get(0)) {
|
let other_f = match other_fs {
|
||||||
(1, Some(o_f)) => o_f,
|
[o_f] => o_f,
|
||||||
_ => {
|
_ => {
|
||||||
cx.span_bug(span,
|
cx.span_bug(span,
|
||||||
"not exactly 2 arguments in `derive(PartialOrd)`")
|
"not exactly 2 arguments in `derive(PartialOrd)`")
|
||||||
|
@ -193,8 +193,8 @@ fn cs_op(less: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
let par_cmp = |cx: &mut ExtCtxt<'_>, span, self_f: P<Expr>, other_fs: &[P<Expr>], default| {
|
let par_cmp = |cx: &mut ExtCtxt<'_>, span, self_f: P<Expr>, other_fs: &[P<Expr>], default| {
|
||||||
let other_f = match (other_fs.len(), other_fs.get(0)) {
|
let other_f = match other_fs {
|
||||||
(1, Some(o_f)) => o_f,
|
[o_f] => o_f,
|
||||||
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
|
_ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,8 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt<'_>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> P<Expr> {
|
fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> P<Expr> {
|
||||||
let state_expr = match (substr.nonself_args.len(), substr.nonself_args.get(0)) {
|
let state_expr = match &substr.nonself_args {
|
||||||
(1, Some(o_f)) => o_f,
|
&[o_f] => o_f,
|
||||||
_ => {
|
_ => {
|
||||||
cx.span_bug(trait_span,
|
cx.span_bug(trait_span,
|
||||||
"incorrect number of arguments in `derive(Hash)`")
|
"incorrect number of arguments in `derive(Hash)`")
|
||||||
|
|
|
@ -28,7 +28,7 @@ enum ArgumentType {
|
||||||
|
|
||||||
enum Position {
|
enum Position {
|
||||||
Exact(usize),
|
Exact(usize),
|
||||||
Named(String),
|
Named(Symbol),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Context<'a, 'b: 'a> {
|
struct Context<'a, 'b: 'a> {
|
||||||
|
@ -57,7 +57,7 @@ struct Context<'a, 'b: 'a> {
|
||||||
/// Unique format specs seen for each argument.
|
/// Unique format specs seen for each argument.
|
||||||
arg_unique_types: Vec<Vec<ArgumentType>>,
|
arg_unique_types: Vec<Vec<ArgumentType>>,
|
||||||
/// Map from named arguments to their resolved indices.
|
/// Map from named arguments to their resolved indices.
|
||||||
names: FxHashMap<String, usize>,
|
names: FxHashMap<Symbol, usize>,
|
||||||
|
|
||||||
/// The latest consecutive literal strings, or empty if there weren't any.
|
/// The latest consecutive literal strings, or empty if there weren't any.
|
||||||
literal: String,
|
literal: String,
|
||||||
|
@ -127,9 +127,9 @@ fn parse_args<'a>(
|
||||||
ecx: &mut ExtCtxt<'a>,
|
ecx: &mut ExtCtxt<'a>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
tts: &[tokenstream::TokenTree]
|
tts: &[tokenstream::TokenTree]
|
||||||
) -> Result<(P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<String, usize>), DiagnosticBuilder<'a>> {
|
) -> Result<(P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, usize>), DiagnosticBuilder<'a>> {
|
||||||
let mut args = Vec::<P<ast::Expr>>::new();
|
let mut args = Vec::<P<ast::Expr>>::new();
|
||||||
let mut names = FxHashMap::<String, usize>::default();
|
let mut names = FxHashMap::<Symbol, usize>::default();
|
||||||
|
|
||||||
let mut p = ecx.new_parser_from_tts(tts);
|
let mut p = ecx.new_parser_from_tts(tts);
|
||||||
|
|
||||||
|
@ -158,11 +158,10 @@ fn parse_args<'a>(
|
||||||
"expected ident, positional arguments cannot follow named arguments",
|
"expected ident, positional arguments cannot follow named arguments",
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let name: &str = &name.as_str();
|
|
||||||
|
|
||||||
p.expect(&token::Eq)?;
|
p.expect(&token::Eq)?;
|
||||||
let e = p.parse_expr()?;
|
let e = p.parse_expr()?;
|
||||||
if let Some(prev) = names.get(name) {
|
if let Some(prev) = names.get(&name) {
|
||||||
ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", name))
|
ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", name))
|
||||||
.span_note(args[*prev].span, "previously here")
|
.span_note(args[*prev].span, "previously here")
|
||||||
.emit();
|
.emit();
|
||||||
|
@ -174,7 +173,7 @@ fn parse_args<'a>(
|
||||||
// if the input is valid, we can simply append to the positional
|
// if the input is valid, we can simply append to the positional
|
||||||
// args. And remember the names.
|
// args. And remember the names.
|
||||||
let slot = args.len();
|
let slot = args.len();
|
||||||
names.insert(name.to_string(), slot);
|
names.insert(name, slot);
|
||||||
args.push(e);
|
args.push(e);
|
||||||
} else {
|
} else {
|
||||||
let e = p.parse_expr()?;
|
let e = p.parse_expr()?;
|
||||||
|
@ -188,7 +187,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
|
fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
|
||||||
// NOTE: the `unwrap_or` branch is needed in case of invalid format
|
// NOTE: the `unwrap_or` branch is needed in case of invalid format
|
||||||
// arguments, e.g., `format_args!("{foo}")`.
|
// arguments, e.g., `format_args!("{foo}")`.
|
||||||
let lookup = |s| *self.names.get(s).unwrap_or(&0);
|
let lookup = |s: Symbol| *self.names.get(&s).unwrap_or(&0);
|
||||||
|
|
||||||
match *p {
|
match *p {
|
||||||
parse::String(_) => {}
|
parse::String(_) => {}
|
||||||
|
@ -222,7 +221,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
// it's written second, so it should come after width/precision.
|
// it's written second, so it should come after width/precision.
|
||||||
let pos = match arg.position {
|
let pos = match arg.position {
|
||||||
parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
|
parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
|
||||||
parse::ArgumentNamed(s) => Named(s.to_string()),
|
parse::ArgumentNamed(s) => Named(s),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty = Placeholder(arg.format.ty.to_string());
|
let ty = Placeholder(arg.format.ty.to_string());
|
||||||
|
@ -232,7 +231,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_count(&mut self, c: parse::Count<'_>) {
|
fn verify_count(&mut self, c: parse::Count) {
|
||||||
match c {
|
match c {
|
||||||
parse::CountImplied |
|
parse::CountImplied |
|
||||||
parse::CountIs(..) => {}
|
parse::CountIs(..) => {}
|
||||||
|
@ -240,7 +239,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
self.verify_arg_type(Exact(i), Count);
|
self.verify_arg_type(Exact(i), Count);
|
||||||
}
|
}
|
||||||
parse::CountIsName(s) => {
|
parse::CountIsName(s) => {
|
||||||
self.verify_arg_type(Named(s.to_string()), Count);
|
self.verify_arg_type(Named(s), Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,7 +389,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
||||||
ecx.std_path(&[sym::fmt, sym::rt, sym::v1, Symbol::intern(s)])
|
ecx.std_path(&[sym::fmt, sym::rt, sym::v1, Symbol::intern(s)])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_count(&self, c: parse::Count<'_>) -> P<ast::Expr> {
|
fn build_count(&self, c: parse::Count) -> P<ast::Expr> {
|
||||||
let sp = self.macsp;
|
let sp = self.macsp;
|
||||||
let count = |c, arg| {
|
let count = |c, arg| {
|
||||||
let mut path = Context::rtpath(self.ecx, "Count");
|
let mut path = Context::rtpath(self.ecx, "Count");
|
||||||
|
@ -739,7 +738,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
efmt: P<ast::Expr>,
|
efmt: P<ast::Expr>,
|
||||||
args: Vec<P<ast::Expr>>,
|
args: Vec<P<ast::Expr>>,
|
||||||
names: FxHashMap<String, usize>,
|
names: FxHashMap<Symbol, usize>,
|
||||||
append_newline: bool)
|
append_newline: bool)
|
||||||
-> P<ast::Expr> {
|
-> P<ast::Expr> {
|
||||||
// NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
|
// NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
|
||||||
|
@ -901,15 +900,15 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>,
|
||||||
|
|
||||||
if !parser.errors.is_empty() {
|
if !parser.errors.is_empty() {
|
||||||
let err = parser.errors.remove(0);
|
let err = parser.errors.remove(0);
|
||||||
let sp = fmt.span.from_inner_byte_pos(err.start.unwrap(), err.end.unwrap());
|
let sp = fmt.span.from_inner(err.span);
|
||||||
let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}",
|
let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}",
|
||||||
err.description));
|
err.description));
|
||||||
e.span_label(sp, err.label + " in format string");
|
e.span_label(sp, err.label + " in format string");
|
||||||
if let Some(note) = err.note {
|
if let Some(note) = err.note {
|
||||||
e.note(¬e);
|
e.note(¬e);
|
||||||
}
|
}
|
||||||
if let Some((label, start, end)) = err.secondary_label {
|
if let Some((label, span)) = err.secondary_label {
|
||||||
let sp = fmt.span.from_inner_byte_pos(start.unwrap(), end.unwrap());
|
let sp = fmt.span.from_inner(span);
|
||||||
e.span_label(sp, label);
|
e.span_label(sp, label);
|
||||||
}
|
}
|
||||||
e.emit();
|
e.emit();
|
||||||
|
@ -917,9 +916,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg_spans = parser.arg_places.iter()
|
let arg_spans = parser.arg_places.iter()
|
||||||
.map(|&(parse::SpanIndex(start), parse::SpanIndex(end))| {
|
.map(|span| fmt.span.from_inner(*span))
|
||||||
fmt.span.from_inner_byte_pos(start, end)
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut cx = Context {
|
let mut cx = Context {
|
||||||
|
@ -1044,7 +1041,9 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>,
|
||||||
let mut show_doc_note = false;
|
let mut show_doc_note = false;
|
||||||
|
|
||||||
let mut suggestions = vec![];
|
let mut suggestions = vec![];
|
||||||
for sub in foreign::$kind::iter_subs(fmt_str) {
|
// account for `"` and account for raw strings `r#`
|
||||||
|
let padding = str_style.map(|i| i + 2).unwrap_or(1);
|
||||||
|
for sub in foreign::$kind::iter_subs(fmt_str, padding) {
|
||||||
let trn = match sub.translate() {
|
let trn = match sub.translate() {
|
||||||
Some(trn) => trn,
|
Some(trn) => trn,
|
||||||
|
|
||||||
|
@ -1064,10 +1063,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>,
|
||||||
show_doc_note = true;
|
show_doc_note = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((start, end)) = pos {
|
if let Some(inner_sp) = pos {
|
||||||
// account for `"` and account for raw strings `r#`
|
let sp = fmt_sp.from_inner(inner_sp);
|
||||||
let padding = str_style.map(|i| i + 2).unwrap_or(1);
|
|
||||||
let sp = fmt_sp.from_inner_byte_pos(start + padding, end + padding);
|
|
||||||
suggestions.push((sp, trn));
|
suggestions.push((sp, trn));
|
||||||
} else {
|
} else {
|
||||||
diag.help(&format!("`{}` should be written as `{}`", sub, trn));
|
diag.help(&format!("`{}` should be written as `{}`", sub, trn));
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod printf {
|
pub mod printf {
|
||||||
use super::strcursor::StrCursor as Cur;
|
use super::strcursor::StrCursor as Cur;
|
||||||
|
use syntax_pos::InnerSpan;
|
||||||
|
|
||||||
/// Represents a single `printf`-style substitution.
|
/// Represents a single `printf`-style substitution.
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
@ -18,7 +19,7 @@ pub mod printf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn position(&self) -> Option<(usize, usize)> {
|
pub fn position(&self) -> Option<InnerSpan> {
|
||||||
match *self {
|
match *self {
|
||||||
Substitution::Format(ref fmt) => Some(fmt.position),
|
Substitution::Format(ref fmt) => Some(fmt.position),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -28,7 +29,7 @@ pub mod printf {
|
||||||
pub fn set_position(&mut self, start: usize, end: usize) {
|
pub fn set_position(&mut self, start: usize, end: usize) {
|
||||||
match self {
|
match self {
|
||||||
Substitution::Format(ref mut fmt) => {
|
Substitution::Format(ref mut fmt) => {
|
||||||
fmt.position = (start, end);
|
fmt.position = InnerSpan::new(start, end);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +66,7 @@ pub mod printf {
|
||||||
/// Type of parameter being converted.
|
/// Type of parameter being converted.
|
||||||
pub type_: &'a str,
|
pub type_: &'a str,
|
||||||
/// Byte offset for the start and end of this formatting directive.
|
/// Byte offset for the start and end of this formatting directive.
|
||||||
pub position: (usize, usize),
|
pub position: InnerSpan,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format<'_> {
|
impl Format<'_> {
|
||||||
|
@ -263,10 +264,10 @@ pub mod printf {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all substitutions in a given string.
|
/// Returns an iterator over all substitutions in a given string.
|
||||||
pub fn iter_subs(s: &str) -> Substitutions<'_> {
|
pub fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> {
|
||||||
Substitutions {
|
Substitutions {
|
||||||
s,
|
s,
|
||||||
pos: 0,
|
pos: start_pos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,9 +283,9 @@ pub mod printf {
|
||||||
let (mut sub, tail) = parse_next_substitution(self.s)?;
|
let (mut sub, tail) = parse_next_substitution(self.s)?;
|
||||||
self.s = tail;
|
self.s = tail;
|
||||||
match sub {
|
match sub {
|
||||||
Substitution::Format(_) => if let Some((start, end)) = sub.position() {
|
Substitution::Format(_) => if let Some(inner_span) = sub.position() {
|
||||||
sub.set_position(start + self.pos, end + self.pos);
|
sub.set_position(inner_span.start + self.pos, inner_span.end + self.pos);
|
||||||
self.pos += end;
|
self.pos += inner_span.end;
|
||||||
}
|
}
|
||||||
Substitution::Escape => self.pos += 2,
|
Substitution::Escape => self.pos += 2,
|
||||||
}
|
}
|
||||||
|
@ -373,7 +374,7 @@ pub mod printf {
|
||||||
precision: None,
|
precision: None,
|
||||||
length: None,
|
length: None,
|
||||||
type_: at.slice_between(next).unwrap(),
|
type_: at.slice_between(next).unwrap(),
|
||||||
position: (start.at, next.at),
|
position: InnerSpan::new(start.at, next.at),
|
||||||
}),
|
}),
|
||||||
next.slice_after()
|
next.slice_after()
|
||||||
));
|
));
|
||||||
|
@ -560,7 +561,7 @@ pub mod printf {
|
||||||
drop(next);
|
drop(next);
|
||||||
|
|
||||||
end = at;
|
end = at;
|
||||||
let position = (start.at, end.at);
|
let position = InnerSpan::new(start.at, end.at);
|
||||||
|
|
||||||
let f = Format {
|
let f = Format {
|
||||||
span: start.slice_between(end).unwrap(),
|
span: start.slice_between(end).unwrap(),
|
||||||
|
@ -650,7 +651,7 @@ pub mod printf {
|
||||||
precision: $prec,
|
precision: $prec,
|
||||||
length: $len,
|
length: $len,
|
||||||
type_: $type_,
|
type_: $type_,
|
||||||
position: $pos,
|
position: syntax_pos::InnerSpan::new($pos.0, $pos.1),
|
||||||
}),
|
}),
|
||||||
"!"
|
"!"
|
||||||
))
|
))
|
||||||
|
@ -711,7 +712,7 @@ pub mod printf {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iter() {
|
fn test_iter() {
|
||||||
let s = "The %d'th word %% is: `%.*s` %!\n";
|
let s = "The %d'th word %% is: `%.*s` %!\n";
|
||||||
let subs: Vec<_> = iter_subs(s).map(|sub| sub.translate()).collect();
|
let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
|
subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
|
||||||
vec![Some("{}"), None, Some("{:.*}"), None]
|
vec![Some("{}"), None, Some("{:.*}"), None]
|
||||||
|
@ -761,6 +762,7 @@ pub mod printf {
|
||||||
|
|
||||||
pub mod shell {
|
pub mod shell {
|
||||||
use super::strcursor::StrCursor as Cur;
|
use super::strcursor::StrCursor as Cur;
|
||||||
|
use syntax_pos::InnerSpan;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub enum Substitution<'a> {
|
pub enum Substitution<'a> {
|
||||||
|
@ -778,11 +780,11 @@ pub mod shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn position(&self) -> Option<(usize, usize)> {
|
pub fn position(&self) -> Option<InnerSpan> {
|
||||||
match self {
|
match self {
|
||||||
Substitution::Ordinal(_, pos) |
|
Substitution::Ordinal(_, pos) |
|
||||||
Substitution::Name(_, pos) |
|
Substitution::Name(_, pos) |
|
||||||
Substitution::Escape(pos) => Some(*pos),
|
Substitution::Escape(pos) => Some(InnerSpan::new(pos.0, pos.1)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -804,10 +806,10 @@ pub mod shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all substitutions in a given string.
|
/// Returns an iterator over all substitutions in a given string.
|
||||||
pub fn iter_subs(s: &str) -> Substitutions<'_> {
|
pub fn iter_subs(s: &str, start_pos: usize) -> Substitutions<'_> {
|
||||||
Substitutions {
|
Substitutions {
|
||||||
s,
|
s,
|
||||||
pos: 0,
|
pos: start_pos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,7 +825,7 @@ pub mod shell {
|
||||||
match parse_next_substitution(self.s) {
|
match parse_next_substitution(self.s) {
|
||||||
Some((mut sub, tail)) => {
|
Some((mut sub, tail)) => {
|
||||||
self.s = tail;
|
self.s = tail;
|
||||||
if let Some((start, end)) = sub.position() {
|
if let Some(InnerSpan { start, end }) = sub.position() {
|
||||||
sub.set_position(start + self.pos, end + self.pos);
|
sub.set_position(start + self.pos, end + self.pos);
|
||||||
self.pos += end;
|
self.pos += end;
|
||||||
}
|
}
|
||||||
|
@ -940,7 +942,7 @@ pub mod shell {
|
||||||
fn test_iter() {
|
fn test_iter() {
|
||||||
use super::iter_subs;
|
use super::iter_subs;
|
||||||
let s = "The $0'th word $$ is: `$WORD` $!\n";
|
let s = "The $0'th word $$ is: `$WORD` $!\n";
|
||||||
let subs: Vec<_> = iter_subs(s).map(|sub| sub.translate()).collect();
|
let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
|
subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::<Vec<_>>(),
|
||||||
vec![Some("{0}"), None, Some("{WORD}")]
|
vec![Some("{0}"), None, Some("{WORD}")]
|
||||||
|
|
|
@ -16,11 +16,11 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt<'_>,
|
||||||
feature_gate::EXPLAIN_TRACE_MACROS);
|
feature_gate::EXPLAIN_TRACE_MACROS);
|
||||||
}
|
}
|
||||||
|
|
||||||
match (tt.len(), tt.first()) {
|
match tt {
|
||||||
(1, Some(TokenTree::Token(token))) if token.is_keyword(kw::True) => {
|
[TokenTree::Token(token)] if token.is_keyword(kw::True) => {
|
||||||
cx.set_trace_macros(true);
|
cx.set_trace_macros(true);
|
||||||
}
|
}
|
||||||
(1, Some(TokenTree::Token(token))) if token.is_keyword(kw::False) => {
|
[TokenTree::Token(token)] if token.is_keyword(kw::False) => {
|
||||||
cx.set_trace_macros(false);
|
cx.set_trace_macros(false);
|
||||||
}
|
}
|
||||||
_ => cx.span_err(sp, "trace_macros! accepts only `true` or `false`"),
|
_ => cx.span_err(sp, "trace_macros! accepts only `true` or `false`"),
|
||||||
|
|
|
@ -505,10 +505,10 @@ impl Span {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_inner_byte_pos(self, start: usize, end: usize) -> Span {
|
pub fn from_inner(self, inner: InnerSpan) -> Span {
|
||||||
let span = self.data();
|
let span = self.data();
|
||||||
Span::new(span.lo + BytePos::from_usize(start),
|
Span::new(span.lo + BytePos::from_usize(inner.start),
|
||||||
span.lo + BytePos::from_usize(end),
|
span.lo + BytePos::from_usize(inner.end),
|
||||||
span.ctxt)
|
span.ctxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1396,6 +1396,18 @@ pub struct MalformedSourceMapPositions {
|
||||||
pub end_pos: BytePos
|
pub end_pos: BytePos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct InnerSpan {
|
||||||
|
pub start: usize,
|
||||||
|
pub end: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InnerSpan {
|
||||||
|
pub fn new(start: usize, end: usize) -> InnerSpan {
|
||||||
|
InnerSpan { start, end }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Given a slice of line start positions and a position, returns the index of
|
// Given a slice of line start positions and a position, returns the index of
|
||||||
// the line the position is on. Returns -1 if the position is located before
|
// the line the position is on. Returns -1 if the position is located before
|
||||||
// the first line.
|
// the first line.
|
||||||
|
|
|
@ -203,6 +203,7 @@ symbols! {
|
||||||
core_intrinsics,
|
core_intrinsics,
|
||||||
crate_id,
|
crate_id,
|
||||||
crate_in_paths,
|
crate_in_paths,
|
||||||
|
crate_local,
|
||||||
crate_name,
|
crate_name,
|
||||||
crate_type,
|
crate_type,
|
||||||
crate_visibility_modifier,
|
crate_visibility_modifier,
|
||||||
|
@ -221,6 +222,7 @@ symbols! {
|
||||||
deref,
|
deref,
|
||||||
deref_mut,
|
deref_mut,
|
||||||
derive,
|
derive,
|
||||||
|
direct,
|
||||||
doc,
|
doc,
|
||||||
doc_alias,
|
doc_alias,
|
||||||
doc_cfg,
|
doc_cfg,
|
||||||
|
@ -278,8 +280,10 @@ symbols! {
|
||||||
format_args_nl,
|
format_args_nl,
|
||||||
from,
|
from,
|
||||||
From,
|
From,
|
||||||
|
from_desugaring,
|
||||||
from_error,
|
from_error,
|
||||||
from_generator,
|
from_generator,
|
||||||
|
from_method,
|
||||||
from_ok,
|
from_ok,
|
||||||
from_usize,
|
from_usize,
|
||||||
fundamental,
|
fundamental,
|
||||||
|
@ -443,6 +447,7 @@ symbols! {
|
||||||
panic_impl,
|
panic_impl,
|
||||||
panic_implementation,
|
panic_implementation,
|
||||||
panic_runtime,
|
panic_runtime,
|
||||||
|
parent_trait,
|
||||||
partial_cmp,
|
partial_cmp,
|
||||||
PartialOrd,
|
PartialOrd,
|
||||||
passes,
|
passes,
|
||||||
|
@ -569,6 +574,7 @@ symbols! {
|
||||||
__rust_unstable_column,
|
__rust_unstable_column,
|
||||||
rvalue_static_promotion,
|
rvalue_static_promotion,
|
||||||
sanitizer_runtime,
|
sanitizer_runtime,
|
||||||
|
_Self,
|
||||||
self_in_typedefs,
|
self_in_typedefs,
|
||||||
self_struct_ctor,
|
self_struct_ctor,
|
||||||
Send,
|
Send,
|
||||||
|
|
Loading…
Reference in New Issue