Auto merge of #75145 - davidtwco:issue-60607-preallocate-defid-for-lang-items, r=petrochenkov
Reference lang items during AST lowering Fixes #60607 and fixes #61019. This PR introduces `QPath::LangItem` to the HIR and uses it in AST lowering instead of constructing a `hir::Path` from a slice of symbols: - Credit for much of this work goes to @matthewjasper, I basically just [rebased their earlier work](a227c706b7 (diff-c0f791ead38d2d02916faaad0f56f41d)
). - ~~Changes to Clippy might not be correct, they compile but attempting to run tests through `./x.py` produced failures which appeared spurious, so I didn't run any clippy tests.~~ - Changes to save analysis might not be correct - tests pass but I don't have a lot of confidence in those changes being correct. - I've used `GenericBounds::LangItemTrait` rather than changing `PolyTraitRef`, as suggested by @matthewjasper [in this comment](a227c706b7 (r40107992)
) but I'd prefer that be left for a follow-up. - I've split things into smaller commits fairly arbitrarily to make the diff easier to review, each commit should compile but might not pass tests until the final commit. r? @oli-obk cc @matthewjasper
This commit is contained in:
commit
792c645ca7
61 changed files with 588 additions and 458 deletions
|
@ -385,6 +385,7 @@ pub trait Into<T>: Sized {
|
||||||
))]
|
))]
|
||||||
pub trait From<T>: Sized {
|
pub trait From<T>: Sized {
|
||||||
/// Performs the conversion.
|
/// Performs the conversion.
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "from")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
fn from(_: T) -> Self;
|
fn from(_: T) -> Self;
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,7 @@ pub trait Future {
|
||||||
/// [`Context`]: ../task/struct.Context.html
|
/// [`Context`]: ../task/struct.Context.html
|
||||||
/// [`Waker`]: ../task/struct.Waker.html
|
/// [`Waker`]: ../task/struct.Waker.html
|
||||||
/// [`Waker::wake`]: ../task/struct.Waker.html#method.wake
|
/// [`Waker::wake`]: ../task/struct.Waker.html#method.wake
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "poll")]
|
||||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ unsafe impl Sync for ResumeTy {}
|
||||||
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
|
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
|
||||||
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
|
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
|
||||||
// This is `const` to avoid extra errors after we recover from `const async fn`
|
// This is `const` to avoid extra errors after we recover from `const async fn`
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "from_generator")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[unstable(feature = "gen_future", issue = "50547")]
|
#[unstable(feature = "gen_future", issue = "50547")]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -85,6 +86,7 @@ where
|
||||||
GenFuture(gen)
|
GenFuture(gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "get_context")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[unstable(feature = "gen_future", issue = "50547")]
|
#[unstable(feature = "gen_future", issue = "50547")]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -235,6 +235,7 @@ pub trait IntoIterator {
|
||||||
/// assert_eq!(Some(3), iter.next());
|
/// assert_eq!(Some(3), iter.next());
|
||||||
/// assert_eq!(None, iter.next());
|
/// assert_eq!(None, iter.next());
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "into_iter")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
fn into_iter(self) -> Self::IntoIter;
|
fn into_iter(self) -> Self::IntoIter;
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,6 +129,7 @@ pub trait Iterator {
|
||||||
/// assert_eq!(None, iter.next());
|
/// assert_eq!(None, iter.next());
|
||||||
/// assert_eq!(None, iter.next());
|
/// assert_eq!(None, iter.next());
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "next")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
fn next(&mut self) -> Option<Self::Item>;
|
fn next(&mut self) -> Option<Self::Item>;
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ use crate::hash::Hash;
|
||||||
/// [`IntoIterator`]: ../iter/trait.Iterator.html
|
/// [`IntoIterator`]: ../iter/trait.Iterator.html
|
||||||
/// [`Iterator`]: ../iter/trait.IntoIterator.html
|
/// [`Iterator`]: ../iter/trait.IntoIterator.html
|
||||||
/// [slicing index]: ../slice/trait.SliceIndex.html
|
/// [slicing index]: ../slice/trait.SliceIndex.html
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "RangeFull")]
|
||||||
#[doc(alias = "..")]
|
#[doc(alias = "..")]
|
||||||
#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
@ -70,6 +71,7 @@ impl fmt::Debug for RangeFull {
|
||||||
/// assert_eq!(arr[1.. 3], [ 1,2 ]); // Range
|
/// assert_eq!(arr[1.. 3], [ 1,2 ]); // Range
|
||||||
/// assert_eq!(arr[1..=3], [ 1,2,3 ]);
|
/// assert_eq!(arr[1..=3], [ 1,2,3 ]);
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "Range")]
|
||||||
#[doc(alias = "..")]
|
#[doc(alias = "..")]
|
||||||
#[derive(Clone, Default, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
#[derive(Clone, Default, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
@ -178,6 +180,7 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> {
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`Iterator`]: ../iter/trait.IntoIterator.html
|
/// [`Iterator`]: ../iter/trait.IntoIterator.html
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "RangeFrom")]
|
||||||
#[doc(alias = "..")]
|
#[doc(alias = "..")]
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
@ -260,6 +263,7 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
|
||||||
/// [`IntoIterator`]: ../iter/trait.Iterator.html
|
/// [`IntoIterator`]: ../iter/trait.Iterator.html
|
||||||
/// [`Iterator`]: ../iter/trait.IntoIterator.html
|
/// [`Iterator`]: ../iter/trait.IntoIterator.html
|
||||||
/// [slicing index]: ../slice/trait.SliceIndex.html
|
/// [slicing index]: ../slice/trait.SliceIndex.html
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "RangeTo")]
|
||||||
#[doc(alias = "..")]
|
#[doc(alias = "..")]
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
@ -328,6 +332,7 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
|
||||||
/// assert_eq!(arr[1.. 3], [ 1,2 ]);
|
/// assert_eq!(arr[1.. 3], [ 1,2 ]);
|
||||||
/// assert_eq!(arr[1..=3], [ 1,2,3 ]); // RangeInclusive
|
/// assert_eq!(arr[1..=3], [ 1,2,3 ]); // RangeInclusive
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "RangeInclusive")]
|
||||||
#[doc(alias = "..=")]
|
#[doc(alias = "..=")]
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
|
||||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||||
|
@ -359,6 +364,7 @@ impl<Idx> RangeInclusive<Idx> {
|
||||||
///
|
///
|
||||||
/// assert_eq!(3..=5, RangeInclusive::new(3, 5));
|
/// assert_eq!(3..=5, RangeInclusive::new(3, 5));
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "range_inclusive_new")]
|
||||||
#[stable(feature = "inclusive_range_methods", since = "1.27.0")]
|
#[stable(feature = "inclusive_range_methods", since = "1.27.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_promotable]
|
#[rustc_promotable]
|
||||||
|
@ -555,6 +561,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
|
||||||
/// [`IntoIterator`]: ../iter/trait.Iterator.html
|
/// [`IntoIterator`]: ../iter/trait.Iterator.html
|
||||||
/// [`Iterator`]: ../iter/trait.IntoIterator.html
|
/// [`Iterator`]: ../iter/trait.IntoIterator.html
|
||||||
/// [slicing index]: ../slice/trait.SliceIndex.html
|
/// [slicing index]: ../slice/trait.SliceIndex.html
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "RangeToInclusive")]
|
||||||
#[doc(alias = "..=")]
|
#[doc(alias = "..=")]
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||||
|
|
|
@ -43,16 +43,19 @@ pub trait Try {
|
||||||
/// in the return type of the enclosing scope (which must itself implement
|
/// in the return type of the enclosing scope (which must itself implement
|
||||||
/// `Try`). Specifically, the value `X::from_error(From::from(e))`
|
/// `Try`). Specifically, the value `X::from_error(From::from(e))`
|
||||||
/// is returned, where `X` is the return type of the enclosing function.
|
/// is returned, where `X` is the return type of the enclosing function.
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "into_result")]
|
||||||
#[unstable(feature = "try_trait", issue = "42327")]
|
#[unstable(feature = "try_trait", issue = "42327")]
|
||||||
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
||||||
|
|
||||||
/// Wrap an error value to construct the composite result. For example,
|
/// Wrap an error value to construct the composite result. For example,
|
||||||
/// `Result::Err(x)` and `Result::from_error(x)` are equivalent.
|
/// `Result::Err(x)` and `Result::from_error(x)` are equivalent.
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "from_error")]
|
||||||
#[unstable(feature = "try_trait", issue = "42327")]
|
#[unstable(feature = "try_trait", issue = "42327")]
|
||||||
fn from_error(v: Self::Error) -> Self;
|
fn from_error(v: Self::Error) -> Self;
|
||||||
|
|
||||||
/// Wrap an OK value to construct the composite result. For example,
|
/// Wrap an OK value to construct the composite result. For example,
|
||||||
/// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent.
|
/// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent.
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "from_ok")]
|
||||||
#[unstable(feature = "try_trait", issue = "42327")]
|
#[unstable(feature = "try_trait", issue = "42327")]
|
||||||
fn from_ok(v: Self::Ok) -> Self;
|
fn from_ok(v: Self::Ok) -> Self;
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,9 +144,11 @@ use crate::{
|
||||||
#[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
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "None")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
None,
|
None,
|
||||||
/// Some value `T`
|
/// Some value `T`
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "Some")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
Some(#[stable(feature = "rust1", since = "1.0.0")] T),
|
Some(#[stable(feature = "rust1", since = "1.0.0")] T),
|
||||||
}
|
}
|
||||||
|
|
|
@ -569,6 +569,7 @@ impl<P: Deref> Pin<P> {
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`mem::swap`]: ../../std/mem/fn.swap.html
|
/// [`mem::swap`]: ../../std/mem/fn.swap.html
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "new_unchecked")]
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
#[stable(feature = "pin", since = "1.33.0")]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn new_unchecked(pointer: P) -> Pin<P> {
|
pub unsafe fn new_unchecked(pointer: P) -> Pin<P> {
|
||||||
|
|
|
@ -246,10 +246,12 @@ use crate::{convert, fmt};
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub enum Result<T, E> {
|
pub enum Result<T, E> {
|
||||||
/// Contains the success value
|
/// Contains the success value
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "Ok")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
|
Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
|
||||||
|
|
||||||
/// Contains the error value
|
/// Contains the error value
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "Err")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
Err(#[stable(feature = "rust1", since = "1.0.0")] E),
|
Err(#[stable(feature = "rust1", since = "1.0.0")] E),
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::result::Result;
|
||||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||||
pub enum Poll<T> {
|
pub enum Poll<T> {
|
||||||
/// Represents that a value is immediately ready.
|
/// Represents that a value is immediately ready.
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "Ready")]
|
||||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||||
Ready(#[stable(feature = "futures_api", since = "1.36.0")] T),
|
Ready(#[stable(feature = "futures_api", since = "1.36.0")] T),
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ pub enum Poll<T> {
|
||||||
/// When a function returns `Pending`, the function *must* also
|
/// When a function returns `Pending`, the function *must* also
|
||||||
/// ensure that the current task is scheduled to be awoken when
|
/// ensure that the current task is scheduled to be awoken when
|
||||||
/// progress can be made.
|
/// progress can be made.
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "Pending")]
|
||||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||||
Pending,
|
Pending,
|
||||||
}
|
}
|
||||||
|
|
|
@ -449,7 +449,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
|
|
||||||
// `::std::ops::Try::from_ok($tail_expr)`
|
// `::std::ops::Try::from_ok($tail_expr)`
|
||||||
block.expr = Some(this.wrap_in_try_constructor(
|
block.expr = Some(this.wrap_in_try_constructor(
|
||||||
sym::from_ok,
|
hir::LangItem::TryFromOk,
|
||||||
try_span,
|
try_span,
|
||||||
tail_expr,
|
tail_expr,
|
||||||
ok_wrapped_span,
|
ok_wrapped_span,
|
||||||
|
@ -461,14 +461,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
|
|
||||||
fn wrap_in_try_constructor(
|
fn wrap_in_try_constructor(
|
||||||
&mut self,
|
&mut self,
|
||||||
method: Symbol,
|
lang_item: hir::LangItem,
|
||||||
method_span: Span,
|
method_span: Span,
|
||||||
expr: &'hir hir::Expr<'hir>,
|
expr: &'hir hir::Expr<'hir>,
|
||||||
overall_span: Span,
|
overall_span: Span,
|
||||||
) -> &'hir hir::Expr<'hir> {
|
) -> &'hir hir::Expr<'hir> {
|
||||||
let path = &[sym::ops, sym::Try, method];
|
|
||||||
let constructor =
|
let constructor =
|
||||||
self.arena.alloc(self.expr_std_path(method_span, path, None, ThinVec::new()));
|
self.arena.alloc(self.expr_lang_item_path(method_span, lang_item, ThinVec::new()));
|
||||||
self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
|
self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,12 +557,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// `future::from_generator`:
|
// `future::from_generator`:
|
||||||
let unstable_span =
|
let unstable_span =
|
||||||
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
|
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
|
||||||
let gen_future = self.expr_std_path(
|
let gen_future =
|
||||||
unstable_span,
|
self.expr_lang_item_path(unstable_span, hir::LangItem::FromGenerator, ThinVec::new());
|
||||||
&[sym::future, sym::from_generator],
|
|
||||||
None,
|
|
||||||
ThinVec::new(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// `future::from_generator(generator)`:
|
// `future::from_generator(generator)`:
|
||||||
hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator])
|
hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator])
|
||||||
|
@ -630,23 +625,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// Use of `await` outside of an async context, we cannot use `task_context` here.
|
// Use of `await` outside of an async context, we cannot use `task_context` here.
|
||||||
self.expr_err(span)
|
self.expr_err(span)
|
||||||
};
|
};
|
||||||
let pin_ty_id = self.next_id();
|
let new_unchecked = self.expr_call_lang_item_fn_mut(
|
||||||
let new_unchecked_expr_kind = self.expr_call_std_assoc_fn(
|
|
||||||
pin_ty_id,
|
|
||||||
span,
|
span,
|
||||||
&[sym::pin, sym::Pin],
|
hir::LangItem::PinNewUnchecked,
|
||||||
"new_unchecked",
|
|
||||||
arena_vec![self; ref_mut_pinned],
|
arena_vec![self; ref_mut_pinned],
|
||||||
);
|
);
|
||||||
let new_unchecked = self.expr(span, new_unchecked_expr_kind, ThinVec::new());
|
let get_context = self.expr_call_lang_item_fn_mut(
|
||||||
let get_context = self.expr_call_std_path_mut(
|
|
||||||
gen_future_span,
|
gen_future_span,
|
||||||
&[sym::future, sym::get_context],
|
hir::LangItem::GetContext,
|
||||||
arena_vec![self; task_context],
|
arena_vec![self; task_context],
|
||||||
);
|
);
|
||||||
let call = self.expr_call_std_path(
|
let call = self.expr_call_lang_item_fn(
|
||||||
span,
|
span,
|
||||||
&[sym::future, sym::Future, sym::poll],
|
hir::LangItem::FuturePoll,
|
||||||
arena_vec![self; new_unchecked, get_context],
|
arena_vec![self; new_unchecked, get_context],
|
||||||
);
|
);
|
||||||
self.arena.alloc(self.expr_unsafe(call))
|
self.arena.alloc(self.expr_unsafe(call))
|
||||||
|
@ -659,11 +650,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let x_ident = Ident::with_dummy_span(sym::result);
|
let x_ident = Ident::with_dummy_span(sym::result);
|
||||||
let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
|
let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
|
||||||
let x_expr = self.expr_ident(span, x_ident, x_pat_hid);
|
let x_expr = self.expr_ident(span, x_ident, x_pat_hid);
|
||||||
let ready_pat = self.pat_std_enum(
|
let ready_field = self.single_pat_field(span, x_pat);
|
||||||
span,
|
let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);
|
||||||
&[sym::task, sym::Poll, sym::Ready],
|
|
||||||
arena_vec![self; x_pat],
|
|
||||||
);
|
|
||||||
let break_x = self.with_loop_scope(loop_node_id, move |this| {
|
let break_x = self.with_loop_scope(loop_node_id, move |this| {
|
||||||
let expr_break =
|
let expr_break =
|
||||||
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
|
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
|
||||||
|
@ -674,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
|
|
||||||
// `::std::task::Poll::Pending => {}`
|
// `::std::task::Poll::Pending => {}`
|
||||||
let pending_arm = {
|
let pending_arm = {
|
||||||
let pending_pat = self.pat_std_enum(span, &[sym::task, sym::Poll, sym::Pending], &[]);
|
let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
|
||||||
let empty_block = self.expr_block_empty(span);
|
let empty_block = self.expr_block_empty(span);
|
||||||
self.arm(pending_pat, empty_block)
|
self.arm(pending_pat, empty_block)
|
||||||
};
|
};
|
||||||
|
@ -842,16 +830,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
|
|
||||||
/// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
|
/// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
|
||||||
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
|
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
|
||||||
let id = self.next_id();
|
|
||||||
let e1 = self.lower_expr_mut(e1);
|
let e1 = self.lower_expr_mut(e1);
|
||||||
let e2 = self.lower_expr_mut(e2);
|
let e2 = self.lower_expr_mut(e2);
|
||||||
self.expr_call_std_assoc_fn(
|
let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span);
|
||||||
id,
|
let fn_expr =
|
||||||
span,
|
self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
|
||||||
&[sym::ops, sym::RangeInclusive],
|
hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
|
||||||
"new",
|
|
||||||
arena_vec![self; e1, e2],
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_expr_range(
|
fn lower_expr_range(
|
||||||
|
@ -863,12 +847,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
) -> hir::ExprKind<'hir> {
|
) -> hir::ExprKind<'hir> {
|
||||||
use rustc_ast::ast::RangeLimits::*;
|
use rustc_ast::ast::RangeLimits::*;
|
||||||
|
|
||||||
let path = match (e1, e2, lims) {
|
let lang_item = match (e1, e2, lims) {
|
||||||
(None, None, HalfOpen) => sym::RangeFull,
|
(None, None, HalfOpen) => hir::LangItem::RangeFull,
|
||||||
(Some(..), None, HalfOpen) => sym::RangeFrom,
|
(Some(..), None, HalfOpen) => hir::LangItem::RangeFrom,
|
||||||
(None, Some(..), HalfOpen) => sym::RangeTo,
|
(None, Some(..), HalfOpen) => hir::LangItem::RangeTo,
|
||||||
(Some(..), Some(..), HalfOpen) => sym::Range,
|
(Some(..), Some(..), HalfOpen) => hir::LangItem::Range,
|
||||||
(None, Some(..), Closed) => sym::RangeToInclusive,
|
(None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
|
||||||
(Some(..), Some(..), Closed) => unreachable!(),
|
(Some(..), Some(..), Closed) => unreachable!(),
|
||||||
(_, None, Closed) => {
|
(_, None, Closed) => {
|
||||||
self.diagnostic().span_fatal(span, "inclusive range with no end").raise()
|
self.diagnostic().span_fatal(span, "inclusive range with no end").raise()
|
||||||
|
@ -883,16 +867,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
let is_unit = fields.is_empty();
|
hir::ExprKind::Struct(self.arena.alloc(hir::QPath::LangItem(lang_item, span)), fields, None)
|
||||||
let struct_path = [sym::ops, path];
|
|
||||||
let struct_path = self.std_path(span, &struct_path, None, is_unit);
|
|
||||||
let struct_path = hir::QPath::Resolved(None, struct_path);
|
|
||||||
|
|
||||||
if is_unit {
|
|
||||||
hir::ExprKind::Path(struct_path)
|
|
||||||
} else {
|
|
||||||
hir::ExprKind::Struct(self.arena.alloc(struct_path), fields, None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
|
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
|
||||||
|
@ -1412,9 +1387,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let match_expr = {
|
let match_expr = {
|
||||||
let iter = self.expr_ident(desugared_span, iter, iter_pat_nid);
|
let iter = self.expr_ident(desugared_span, iter, iter_pat_nid);
|
||||||
let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter);
|
let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter);
|
||||||
let next_path = &[sym::iter, sym::Iterator, sym::next];
|
let next_expr = self.expr_call_lang_item_fn(
|
||||||
let next_expr =
|
desugared_span,
|
||||||
self.expr_call_std_path(desugared_span, next_path, arena_vec![self; ref_mut_iter]);
|
hir::LangItem::IteratorNext,
|
||||||
|
arena_vec![self; ref_mut_iter],
|
||||||
|
);
|
||||||
let arms = arena_vec![self; pat_arm, break_arm];
|
let arms = arena_vec![self; pat_arm, break_arm];
|
||||||
|
|
||||||
self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
|
self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
|
||||||
|
@ -1472,8 +1449,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
|
|
||||||
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
|
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
|
||||||
let into_iter_expr = {
|
let into_iter_expr = {
|
||||||
let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter];
|
self.expr_call_lang_item_fn(
|
||||||
self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head])
|
into_iter_span,
|
||||||
|
hir::LangItem::IntoIterIntoIter,
|
||||||
|
arena_vec![self; head],
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let match_expr = self.arena.alloc(self.expr_match(
|
let match_expr = self.arena.alloc(self.expr_match(
|
||||||
|
@ -1521,8 +1501,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// expand <expr>
|
// expand <expr>
|
||||||
let sub_expr = self.lower_expr_mut(sub_expr);
|
let sub_expr = self.lower_expr_mut(sub_expr);
|
||||||
|
|
||||||
let path = &[sym::ops, sym::Try, sym::into_result];
|
self.expr_call_lang_item_fn(
|
||||||
self.expr_call_std_path(unstable_span, path, arena_vec![self; sub_expr])
|
unstable_span,
|
||||||
|
hir::LangItem::TryIntoResult,
|
||||||
|
arena_vec![self; sub_expr],
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
// `#[allow(unreachable_code)]`
|
// `#[allow(unreachable_code)]`
|
||||||
|
@ -1558,12 +1541,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
let err_ident = Ident::with_dummy_span(sym::err);
|
let err_ident = Ident::with_dummy_span(sym::err);
|
||||||
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
|
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
|
||||||
let from_expr = {
|
let from_expr = {
|
||||||
let from_path = &[sym::convert, sym::From, sym::from];
|
|
||||||
let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid);
|
let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid);
|
||||||
self.expr_call_std_path(try_span, from_path, arena_vec![self; err_expr])
|
self.expr_call_lang_item_fn(
|
||||||
|
try_span,
|
||||||
|
hir::LangItem::FromFrom,
|
||||||
|
arena_vec![self; err_expr],
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let from_err_expr =
|
let from_err_expr = self.wrap_in_try_constructor(
|
||||||
self.wrap_in_try_constructor(sym::from_error, unstable_span, from_expr, try_span);
|
hir::LangItem::TryFromError,
|
||||||
|
unstable_span,
|
||||||
|
from_expr,
|
||||||
|
try_span,
|
||||||
|
);
|
||||||
let thin_attrs = ThinVec::from(attrs);
|
let thin_attrs = ThinVec::from(attrs);
|
||||||
let catch_scope = self.catch_scopes.last().copied();
|
let catch_scope = self.catch_scopes.last().copied();
|
||||||
let ret_expr = if let Some(catch_node) = catch_scope {
|
let ret_expr = if let Some(catch_node) = catch_scope {
|
||||||
|
@ -1674,63 +1664,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
self.arena.alloc(self.expr_call_mut(span, e, args))
|
self.arena.alloc(self.expr_call_mut(span, e, args))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: associated functions must use `expr_call_std_path`.
|
fn expr_call_lang_item_fn_mut(
|
||||||
fn expr_call_std_path_mut(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
path_components: &[Symbol],
|
lang_item: hir::LangItem,
|
||||||
args: &'hir [hir::Expr<'hir>],
|
args: &'hir [hir::Expr<'hir>],
|
||||||
) -> hir::Expr<'hir> {
|
) -> hir::Expr<'hir> {
|
||||||
let path =
|
let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new()));
|
||||||
self.arena.alloc(self.expr_std_path(span, path_components, None, ThinVec::new()));
|
|
||||||
self.expr_call_mut(span, path, args)
|
self.expr_call_mut(span, path, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_call_std_path(
|
fn expr_call_lang_item_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
path_components: &[Symbol],
|
lang_item: hir::LangItem,
|
||||||
args: &'hir [hir::Expr<'hir>],
|
args: &'hir [hir::Expr<'hir>],
|
||||||
) -> &'hir hir::Expr<'hir> {
|
) -> &'hir hir::Expr<'hir> {
|
||||||
self.arena.alloc(self.expr_call_std_path_mut(span, path_components, args))
|
self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an expression calling an associated function of an std type.
|
fn expr_lang_item_path(
|
||||||
//
|
|
||||||
// Associated functions cannot be resolved through the normal `std_path` function,
|
|
||||||
// as they are resolved differently and so cannot use `expr_call_std_path`.
|
|
||||||
//
|
|
||||||
// This function accepts the path component (`ty_path_components`) separately from
|
|
||||||
// the name of the associated function (`assoc_fn_name`) in order to facilitate
|
|
||||||
// separate resolution of the type and creation of a path referring to its associated
|
|
||||||
// function.
|
|
||||||
fn expr_call_std_assoc_fn(
|
|
||||||
&mut self,
|
|
||||||
ty_path_id: hir::HirId,
|
|
||||||
span: Span,
|
|
||||||
ty_path_components: &[Symbol],
|
|
||||||
assoc_fn_name: &str,
|
|
||||||
args: &'hir [hir::Expr<'hir>],
|
|
||||||
) -> hir::ExprKind<'hir> {
|
|
||||||
let ty_path = self.std_path(span, ty_path_components, None, false);
|
|
||||||
let ty =
|
|
||||||
self.arena.alloc(self.ty_path(ty_path_id, span, hir::QPath::Resolved(None, ty_path)));
|
|
||||||
let fn_seg = self.arena.alloc(hir::PathSegment::from_ident(Ident::from_str(assoc_fn_name)));
|
|
||||||
let fn_path = hir::QPath::TypeRelative(ty, fn_seg);
|
|
||||||
let fn_expr =
|
|
||||||
self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
|
|
||||||
hir::ExprKind::Call(fn_expr, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expr_std_path(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
components: &[Symbol],
|
lang_item: hir::LangItem,
|
||||||
params: Option<&'hir hir::GenericArgs<'hir>>,
|
|
||||||
attrs: AttrVec,
|
attrs: AttrVec,
|
||||||
) -> hir::Expr<'hir> {
|
) -> hir::Expr<'hir> {
|
||||||
let path = self.std_path(span, components, params, true);
|
self.expr(span, hir::ExprKind::Path(hir::QPath::LangItem(lang_item, span)), attrs)
|
||||||
self.expr(span, hir::ExprKind::Path(hir::QPath::Resolved(None, path)), attrs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn expr_ident(
|
pub(super) fn expr_ident(
|
||||||
|
|
|
@ -85,8 +85,6 @@ const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
|
||||||
rustc_hir::arena_types!(rustc_arena::declare_arena, [], 'tcx);
|
rustc_hir::arena_types!(rustc_arena::declare_arena, [], 'tcx);
|
||||||
|
|
||||||
struct LoweringContext<'a, 'hir: 'a> {
|
struct LoweringContext<'a, 'hir: 'a> {
|
||||||
crate_root: Option<Symbol>,
|
|
||||||
|
|
||||||
/// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
|
/// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
|
|
||||||
|
@ -189,16 +187,6 @@ pub trait ResolverAstLowering {
|
||||||
/// This should only return `None` during testing.
|
/// This should only return `None` during testing.
|
||||||
fn definitions(&mut self) -> &mut Definitions;
|
fn definitions(&mut self) -> &mut Definitions;
|
||||||
|
|
||||||
/// Given suffix `["b", "c", "d"]`, creates an AST path for `[::crate_root]::b::c::d` and
|
|
||||||
/// resolves it based on `is_value`.
|
|
||||||
fn resolve_str_path(
|
|
||||||
&mut self,
|
|
||||||
span: Span,
|
|
||||||
crate_root: Option<Symbol>,
|
|
||||||
components: &[Symbol],
|
|
||||||
ns: Namespace,
|
|
||||||
) -> (ast::Path, Res<NodeId>);
|
|
||||||
|
|
||||||
fn lint_buffer(&mut self) -> &mut LintBuffer;
|
fn lint_buffer(&mut self) -> &mut LintBuffer;
|
||||||
|
|
||||||
fn next_node_id(&mut self) -> NodeId;
|
fn next_node_id(&mut self) -> NodeId;
|
||||||
|
@ -305,7 +293,6 @@ pub fn lower_crate<'a, 'hir>(
|
||||||
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
|
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
|
||||||
|
|
||||||
LoweringContext {
|
LoweringContext {
|
||||||
crate_root: sess.parse_sess.injected_crate_name.get().copied(),
|
|
||||||
sess,
|
sess,
|
||||||
resolver,
|
resolver,
|
||||||
nt_to_tokenstream,
|
nt_to_tokenstream,
|
||||||
|
@ -2064,23 +2051,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// "<Output = T>"
|
// "<Output = T>"
|
||||||
let future_params = self.arena.alloc(hir::GenericArgs {
|
let future_args = self.arena.alloc(hir::GenericArgs {
|
||||||
args: &[],
|
args: &[],
|
||||||
bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
|
bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
|
||||||
parenthesized: false,
|
parenthesized: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ::std::future::Future<future_params>
|
hir::GenericBound::LangItemTrait(
|
||||||
let future_path =
|
// ::std::future::Future<future_params>
|
||||||
self.std_path(span, &[sym::future, sym::Future], Some(future_params), false);
|
hir::LangItem::FutureTraitLangItem,
|
||||||
|
span,
|
||||||
hir::GenericBound::Trait(
|
self.next_id(),
|
||||||
hir::PolyTraitRef {
|
future_args,
|
||||||
trait_ref: hir::TraitRef { path: future_path, hir_ref_id: self.next_id() },
|
|
||||||
bound_generic_params: &[],
|
|
||||||
span,
|
|
||||||
},
|
|
||||||
hir::TraitBoundModifier::None,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2480,35 +2462,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
||||||
self.pat_std_enum(span, &[sym::result, sym::Result, sym::Ok], arena_vec![self; pat])
|
let field = self.single_pat_field(span, pat);
|
||||||
|
self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
||||||
self.pat_std_enum(span, &[sym::result, sym::Result, sym::Err], arena_vec![self; pat])
|
let field = self.single_pat_field(span, pat);
|
||||||
|
self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
|
||||||
self.pat_std_enum(span, &[sym::option, sym::Option, sym::Some], arena_vec![self; pat])
|
let field = self.single_pat_field(span, pat);
|
||||||
|
self.pat_lang_item_variant(span, hir::LangItem::OptionSome, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_none(&mut self, span: Span) -> &'hir hir::Pat<'hir> {
|
fn pat_none(&mut self, span: Span) -> &'hir hir::Pat<'hir> {
|
||||||
self.pat_std_enum(span, &[sym::option, sym::Option, sym::None], &[])
|
self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_std_enum(
|
fn single_pat_field(
|
||||||
&mut self,
|
&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
components: &[Symbol],
|
pat: &'hir hir::Pat<'hir>,
|
||||||
subpats: &'hir [&'hir hir::Pat<'hir>],
|
) -> &'hir [hir::FieldPat<'hir>] {
|
||||||
) -> &'hir hir::Pat<'hir> {
|
let field = hir::FieldPat {
|
||||||
let path = self.std_path(span, components, None, true);
|
hir_id: self.next_id(),
|
||||||
let qpath = hir::QPath::Resolved(None, path);
|
ident: Ident::new(sym::integer(0), span),
|
||||||
let pt = if subpats.is_empty() {
|
is_shorthand: false,
|
||||||
hir::PatKind::Path(qpath)
|
pat,
|
||||||
} else {
|
span,
|
||||||
hir::PatKind::TupleStruct(qpath, subpats, None)
|
|
||||||
};
|
};
|
||||||
self.pat(span, pt)
|
arena_vec![self; field]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pat_lang_item_variant(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
lang_item: hir::LangItem,
|
||||||
|
fields: &'hir [hir::FieldPat<'hir>],
|
||||||
|
) -> &'hir hir::Pat<'hir> {
|
||||||
|
let qpath = hir::QPath::LangItem(lang_item, span);
|
||||||
|
self.pat(span, hir::PatKind::Struct(qpath, fields, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, hir::HirId) {
|
fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, hir::HirId) {
|
||||||
|
@ -2541,42 +2535,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
self.arena.alloc(hir::Pat { hir_id: self.next_id(), kind, span })
|
self.arena.alloc(hir::Pat { hir_id: self.next_id(), kind, span })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a suffix `["b", "c", "d"]`, returns path `::std::b::c::d` when
|
|
||||||
/// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
|
|
||||||
/// The path is also resolved according to `is_value`.
|
|
||||||
fn std_path(
|
|
||||||
&mut self,
|
|
||||||
span: Span,
|
|
||||||
components: &[Symbol],
|
|
||||||
params: Option<&'hir hir::GenericArgs<'hir>>,
|
|
||||||
is_value: bool,
|
|
||||||
) -> &'hir hir::Path<'hir> {
|
|
||||||
let ns = if is_value { Namespace::ValueNS } else { Namespace::TypeNS };
|
|
||||||
let (path, res) = self.resolver.resolve_str_path(span, self.crate_root, components, ns);
|
|
||||||
|
|
||||||
let mut segments: Vec<_> = path
|
|
||||||
.segments
|
|
||||||
.iter()
|
|
||||||
.map(|segment| {
|
|
||||||
let res = self.expect_full_res(segment.id);
|
|
||||||
hir::PathSegment {
|
|
||||||
ident: segment.ident,
|
|
||||||
hir_id: Some(self.lower_node_id(segment.id)),
|
|
||||||
res: Some(self.lower_res(res)),
|
|
||||||
infer_args: true,
|
|
||||||
args: None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
segments.last_mut().unwrap().args = params;
|
|
||||||
|
|
||||||
self.arena.alloc(hir::Path {
|
|
||||||
span,
|
|
||||||
res: res.map_id(|_| panic!("unexpected `NodeId`")),
|
|
||||||
segments: self.arena.alloc_from_iter(segments),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ty_path(
|
fn ty_path(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut hir_id: hir::HirId,
|
mut hir_id: hir::HirId,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::def::{DefKind, Namespace, Res};
|
use crate::def::{DefKind, Namespace, Res};
|
||||||
use crate::def_id::DefId;
|
use crate::def_id::DefId;
|
||||||
crate use crate::hir_id::HirId;
|
crate use crate::hir_id::HirId;
|
||||||
use crate::itemlikevisit;
|
use crate::{itemlikevisit, LangItem};
|
||||||
|
|
||||||
use rustc_ast::ast::{self, CrateSugar, LlvmAsmDialect};
|
use rustc_ast::ast::{self, CrateSugar, LlvmAsmDialect};
|
||||||
use rustc_ast::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy};
|
use rustc_ast::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy};
|
||||||
|
@ -13,7 +13,7 @@ use rustc_ast::util::parser::ExprPrecedence;
|
||||||
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
|
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
|
||||||
use rustc_macros::HashStable_Generic;
|
use rustc_macros::HashStable_Generic;
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::source_map::{SourceMap, Spanned};
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
||||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||||
|
@ -363,6 +363,8 @@ pub enum TraitBoundModifier {
|
||||||
#[derive(Debug, HashStable_Generic)]
|
#[derive(Debug, HashStable_Generic)]
|
||||||
pub enum GenericBound<'hir> {
|
pub enum GenericBound<'hir> {
|
||||||
Trait(PolyTraitRef<'hir>, TraitBoundModifier),
|
Trait(PolyTraitRef<'hir>, TraitBoundModifier),
|
||||||
|
// FIXME(davidtwco): Introduce `PolyTraitRef::LangItem`
|
||||||
|
LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>),
|
||||||
Outlives(Lifetime),
|
Outlives(Lifetime),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,6 +379,7 @@ impl GenericBound<'_> {
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
&GenericBound::Trait(ref t, ..) => t.span,
|
&GenericBound::Trait(ref t, ..) => t.span,
|
||||||
|
&GenericBound::LangItemTrait(_, span, ..) => span,
|
||||||
&GenericBound::Outlives(ref l) => l.span,
|
&GenericBound::Outlives(ref l) => l.span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1419,10 +1422,10 @@ impl Expr<'_> {
|
||||||
self.is_place_expr(|_| true)
|
self.is_place_expr(|_| true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whether this is a place expression.
|
/// Whether this is a place expression.
|
||||||
// `allow_projections_from` should return `true` if indexing a field or
|
///
|
||||||
// index expression based on the given expression should be considered a
|
/// `allow_projections_from` should return `true` if indexing a field or index expression based
|
||||||
// place expression.
|
/// on the given expression should be considered a place expression.
|
||||||
pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool {
|
pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
ExprKind::Path(QPath::Resolved(_, ref path)) => match path.res {
|
ExprKind::Path(QPath::Resolved(_, ref path)) => match path.res {
|
||||||
|
@ -1441,6 +1444,9 @@ impl Expr<'_> {
|
||||||
allow_projections_from(base) || base.is_place_expr(allow_projections_from)
|
allow_projections_from(base) || base.is_place_expr(allow_projections_from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lang item paths cannot currently be local variables or statics.
|
||||||
|
ExprKind::Path(QPath::LangItem(..)) => false,
|
||||||
|
|
||||||
// Partially qualified paths in expressions can only legally
|
// Partially qualified paths in expressions can only legally
|
||||||
// refer to associated items which are always rvalues.
|
// refer to associated items which are always rvalues.
|
||||||
ExprKind::Path(QPath::TypeRelative(..))
|
ExprKind::Path(QPath::TypeRelative(..))
|
||||||
|
@ -1489,58 +1495,28 @@ impl Expr<'_> {
|
||||||
|
|
||||||
/// Checks if the specified expression is a built-in range literal.
|
/// Checks if the specified expression is a built-in range literal.
|
||||||
/// (See: `LoweringContext::lower_expr()`).
|
/// (See: `LoweringContext::lower_expr()`).
|
||||||
///
|
pub fn is_range_literal(expr: &Expr<'_>) -> bool {
|
||||||
/// FIXME(#60607): This function is a hack. If and when we have `QPath::Lang(...)`,
|
|
||||||
/// we can use that instead as simpler, more reliable mechanism, as opposed to using `SourceMap`.
|
|
||||||
pub fn is_range_literal(sm: &SourceMap, expr: &Expr<'_>) -> bool {
|
|
||||||
// Returns whether the given path represents a (desugared) range,
|
|
||||||
// either in std or core, i.e. has either a `::std::ops::Range` or
|
|
||||||
// `::core::ops::Range` prefix.
|
|
||||||
fn is_range_path(path: &Path<'_>) -> bool {
|
|
||||||
let segs: Vec<_> = path.segments.iter().map(|seg| seg.ident.to_string()).collect();
|
|
||||||
let segs: Vec<_> = segs.iter().map(|seg| &**seg).collect();
|
|
||||||
|
|
||||||
// "{{root}}" is the equivalent of `::` prefix in `Path`.
|
|
||||||
if let ["{{root}}", std_core, "ops", range] = segs.as_slice() {
|
|
||||||
(*std_core == "std" || *std_core == "core") && range.starts_with("Range")
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check whether a span corresponding to a range expression is a
|
|
||||||
// range literal, rather than an explicit struct or `new()` call.
|
|
||||||
fn is_lit(sm: &SourceMap, span: &Span) -> bool {
|
|
||||||
sm.span_to_snippet(*span).map(|range_src| range_src.contains("..")).unwrap_or(false)
|
|
||||||
};
|
|
||||||
|
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
// All built-in range literals but `..=` and `..` desugar to `Struct`s.
|
// All built-in range literals but `..=` and `..` desugar to `Struct`s.
|
||||||
ExprKind::Struct(ref qpath, _, _) => {
|
ExprKind::Struct(ref qpath, _, _) => matches!(
|
||||||
if let QPath::Resolved(None, ref path) = **qpath {
|
**qpath,
|
||||||
return is_range_path(&path) && is_lit(sm, &expr.span);
|
QPath::LangItem(
|
||||||
}
|
LangItem::Range
|
||||||
}
|
| LangItem::RangeTo
|
||||||
|
| LangItem::RangeFrom
|
||||||
// `..` desugars to its struct path.
|
| LangItem::RangeFull
|
||||||
ExprKind::Path(QPath::Resolved(None, ref path)) => {
|
| LangItem::RangeToInclusive,
|
||||||
return is_range_path(&path) && is_lit(sm, &expr.span);
|
_,
|
||||||
}
|
)
|
||||||
|
),
|
||||||
|
|
||||||
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
|
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
|
||||||
ExprKind::Call(ref func, _) => {
|
ExprKind::Call(ref func, _) => {
|
||||||
if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind {
|
matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, _)))
|
||||||
if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind {
|
|
||||||
let new_call = segment.ident.name == sym::new;
|
|
||||||
return is_range_path(&path) && is_lit(sm, &expr.span) && new_call;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, HashStable_Generic)]
|
#[derive(Debug, HashStable_Generic)]
|
||||||
|
@ -1677,6 +1653,40 @@ pub enum QPath<'hir> {
|
||||||
/// `<Vec>::new`, and `T::X::Y::method` into `<<<T>::X>::Y>::method`,
|
/// `<Vec>::new`, and `T::X::Y::method` into `<<<T>::X>::Y>::method`,
|
||||||
/// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`.
|
/// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`.
|
||||||
TypeRelative(&'hir Ty<'hir>, &'hir PathSegment<'hir>),
|
TypeRelative(&'hir Ty<'hir>, &'hir PathSegment<'hir>),
|
||||||
|
|
||||||
|
/// Reference to a `#[lang = "foo"]` item.
|
||||||
|
LangItem(LangItem, Span),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'hir> QPath<'hir> {
|
||||||
|
/// Returns the span of this `QPath`.
|
||||||
|
pub fn span(&self) -> Span {
|
||||||
|
match *self {
|
||||||
|
QPath::Resolved(_, path) => path.span,
|
||||||
|
QPath::TypeRelative(_, ps) => ps.ident.span,
|
||||||
|
QPath::LangItem(_, span) => span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the span of the qself of this `QPath`. For example, `()` in
|
||||||
|
/// `<() as Trait>::method`.
|
||||||
|
pub fn qself_span(&self) -> Span {
|
||||||
|
match *self {
|
||||||
|
QPath::Resolved(_, path) => path.span,
|
||||||
|
QPath::TypeRelative(qself, _) => qself.span,
|
||||||
|
QPath::LangItem(_, span) => span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the span of the last segment of this `QPath`. For example, `method` in
|
||||||
|
/// `<() as Trait>::method`.
|
||||||
|
pub fn last_segment_span(&self) -> Span {
|
||||||
|
match *self {
|
||||||
|
QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span,
|
||||||
|
QPath::TypeRelative(_, segment) => segment.ident.span,
|
||||||
|
QPath::LangItem(_, span) => span,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hints at the original code for a let statement.
|
/// Hints at the original code for a let statement.
|
||||||
|
|
|
@ -724,6 +724,7 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(
|
||||||
visitor.visit_ty(qself);
|
visitor.visit_ty(qself);
|
||||||
visitor.visit_path_segment(span, segment);
|
visitor.visit_path_segment(span, segment);
|
||||||
}
|
}
|
||||||
|
QPath::LangItem(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,6 +839,10 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericB
|
||||||
GenericBound::Trait(ref typ, modifier) => {
|
GenericBound::Trait(ref typ, modifier) => {
|
||||||
visitor.visit_poly_trait_ref(typ, modifier);
|
visitor.visit_poly_trait_ref(typ, modifier);
|
||||||
}
|
}
|
||||||
|
GenericBound::LangItemTrait(_, span, hir_id, args) => {
|
||||||
|
visitor.visit_id(hir_id);
|
||||||
|
visitor.visit_generic_args(span, args);
|
||||||
|
}
|
||||||
GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
|
GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
pub use self::LangItem::*;
|
pub use self::LangItem::*;
|
||||||
|
|
||||||
use crate::def_id::DefId;
|
use crate::def_id::DefId;
|
||||||
use crate::Target;
|
use crate::{MethodKind, Target};
|
||||||
|
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
@ -307,4 +307,38 @@ language_item_table! {
|
||||||
CountCodeRegionFnLangItem, sym::count_code_region, count_code_region_fn, Target::Fn;
|
CountCodeRegionFnLangItem, sym::count_code_region, count_code_region_fn, Target::Fn;
|
||||||
CoverageCounterAddFnLangItem, sym::coverage_counter_add, coverage_counter_add_fn, Target::Fn;
|
CoverageCounterAddFnLangItem, sym::coverage_counter_add, coverage_counter_add_fn, Target::Fn;
|
||||||
CoverageCounterSubtractFnLangItem, sym::coverage_counter_subtract, coverage_counter_subtract_fn, Target::Fn;
|
CoverageCounterSubtractFnLangItem, sym::coverage_counter_subtract, coverage_counter_subtract_fn, Target::Fn;
|
||||||
|
|
||||||
|
// Language items from AST lowering
|
||||||
|
TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false });
|
||||||
|
TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false });
|
||||||
|
TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false });
|
||||||
|
|
||||||
|
PollReady, sym::Ready, poll_ready_variant, Target::Variant;
|
||||||
|
PollPending, sym::Pending, poll_pending_variant, Target::Variant;
|
||||||
|
|
||||||
|
FromGenerator, sym::from_generator, from_generator_fn, Target::Fn;
|
||||||
|
GetContext, sym::get_context, get_context_fn, Target::Fn;
|
||||||
|
|
||||||
|
FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false });
|
||||||
|
|
||||||
|
FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false });
|
||||||
|
|
||||||
|
OptionSome, sym::Some, option_some_variant, Target::Variant;
|
||||||
|
OptionNone, sym::None, option_none_variant, Target::Variant;
|
||||||
|
|
||||||
|
ResultOk, sym::Ok, result_ok_variant, Target::Variant;
|
||||||
|
ResultErr, sym::Err, result_err_variant, Target::Variant;
|
||||||
|
|
||||||
|
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false });
|
||||||
|
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false});
|
||||||
|
|
||||||
|
PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent);
|
||||||
|
|
||||||
|
RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct;
|
||||||
|
RangeFull, sym::RangeFull, range_full_struct, Target::Struct;
|
||||||
|
RangeInclusiveStruct, sym::RangeInclusive, range_inclusive_struct, Target::Struct;
|
||||||
|
RangeInclusiveNew, sym::range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent);
|
||||||
|
Range, sym::Range, range_struct, Target::Struct;
|
||||||
|
RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct;
|
||||||
|
RangeTo, sym::RangeTo, range_to_struct, Target::Struct;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ pub enum Target {
|
||||||
TyAlias,
|
TyAlias,
|
||||||
OpaqueTy,
|
OpaqueTy,
|
||||||
Enum,
|
Enum,
|
||||||
|
Variant,
|
||||||
Struct,
|
Struct,
|
||||||
Union,
|
Union,
|
||||||
Trait,
|
Trait,
|
||||||
|
@ -62,6 +63,7 @@ impl Display for Target {
|
||||||
Target::TyAlias => "type alias",
|
Target::TyAlias => "type alias",
|
||||||
Target::OpaqueTy => "opaque type",
|
Target::OpaqueTy => "opaque type",
|
||||||
Target::Enum => "enum",
|
Target::Enum => "enum",
|
||||||
|
Target::Variant => "enum variant",
|
||||||
Target::Struct => "struct",
|
Target::Struct => "struct",
|
||||||
Target::Union => "union",
|
Target::Union => "union",
|
||||||
Target::Trait => "trait",
|
Target::Trait => "trait",
|
||||||
|
|
|
@ -1729,6 +1729,11 @@ impl<'a> State<'a> {
|
||||||
colons_before_params,
|
colons_before_params,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
hir::QPath::LangItem(lang_item, span) => {
|
||||||
|
self.s.word("#[lang = \"");
|
||||||
|
self.print_ident(Ident::new(lang_item.name(), span));
|
||||||
|
self.s.word("\"]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2142,6 +2147,11 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
self.print_poly_trait_ref(tref);
|
self.print_poly_trait_ref(tref);
|
||||||
}
|
}
|
||||||
|
GenericBound::LangItemTrait(lang_item, span, ..) => {
|
||||||
|
self.s.word("#[lang = \"");
|
||||||
|
self.print_ident(Ident::new(lang_item.name(), *span));
|
||||||
|
self.s.word("\"]");
|
||||||
|
}
|
||||||
GenericBound::Outlives(lt) => {
|
GenericBound::Outlives(lt) => {
|
||||||
self.print_lifetime(lt);
|
self.print_lifetime(lt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1057,7 +1057,7 @@ impl TypeAliasBounds {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::QPath::Resolved(..) => false,
|
hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -703,7 +703,7 @@ impl<'tcx> LateContext<'tcx> {
|
||||||
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
|
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
|
||||||
match *qpath {
|
match *qpath {
|
||||||
hir::QPath::Resolved(_, ref path) => path.res,
|
hir::QPath::Resolved(_, ref path) => path.res,
|
||||||
hir::QPath::TypeRelative(..) => self
|
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
|
||||||
.maybe_typeck_results()
|
.maybe_typeck_results()
|
||||||
.and_then(|typeck_results| typeck_results.type_dependent_def(id))
|
.and_then(|typeck_results| typeck_results.type_dependent_def(id))
|
||||||
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
|
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
|
||||||
|
|
|
@ -258,7 +258,7 @@ fn lint_int_literal<'tcx>(
|
||||||
let par_id = cx.tcx.hir().get_parent_node(e.hir_id);
|
let par_id = cx.tcx.hir().get_parent_node(e.hir_id);
|
||||||
if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) {
|
if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) {
|
||||||
if let hir::ExprKind::Struct(..) = par_e.kind {
|
if let hir::ExprKind::Struct(..) = par_e.kind {
|
||||||
if is_range_literal(cx.sess().source_map(), par_e)
|
if is_range_literal(par_e)
|
||||||
&& lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str())
|
&& lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str())
|
||||||
{
|
{
|
||||||
// The overflowing literal lint was overridden.
|
// The overflowing literal lint was overridden.
|
||||||
|
@ -317,7 +317,7 @@ fn lint_uint_literal<'tcx>(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ExprKind::Struct(..) if is_range_literal(cx.sess().source_map(), par_e) => {
|
hir::ExprKind::Struct(..) if is_range_literal(par_e) => {
|
||||||
let t = t.name_str();
|
let t = t.name_str();
|
||||||
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) {
|
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) {
|
||||||
// The overflowing literal lint was overridden.
|
// The overflowing literal lint was overridden.
|
||||||
|
|
|
@ -452,7 +452,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||||
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
|
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
|
||||||
match *qpath {
|
match *qpath {
|
||||||
hir::QPath::Resolved(_, ref path) => path.res,
|
hir::QPath::Resolved(_, ref path) => path.res,
|
||||||
hir::QPath::TypeRelative(..) => self
|
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
|
||||||
.type_dependent_def(id)
|
.type_dependent_def(id)
|
||||||
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
|
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,13 @@ struct LanguageItemCollector<'tcx> {
|
||||||
|
|
||||||
impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
|
impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
|
||||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||||
self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs)
|
self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs);
|
||||||
|
|
||||||
|
if let hir::ItemKind::Enum(def, ..) = &item.kind {
|
||||||
|
for variant in def.variants {
|
||||||
|
self.check_for_lang(Target::Variant, variant.id, variant.attrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
|
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
|
||||||
|
|
|
@ -526,7 +526,8 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||||
| hir::ExprKind::Yield(..)
|
| hir::ExprKind::Yield(..)
|
||||||
| hir::ExprKind::Type(..)
|
| hir::ExprKind::Type(..)
|
||||||
| hir::ExprKind::Err
|
| hir::ExprKind::Err
|
||||||
| hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
|
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
|
||||||
|
| hir::ExprKind::Path(hir::QPath::LangItem(..)) => {
|
||||||
intravisit::walk_expr(ir, expr);
|
intravisit::walk_expr(ir, expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1310,7 +1311,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
|
|
||||||
hir::ExprKind::Lit(..)
|
hir::ExprKind::Lit(..)
|
||||||
| hir::ExprKind::Err
|
| hir::ExprKind::Err
|
||||||
| hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => succ,
|
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
|
||||||
|
| hir::ExprKind::Path(hir::QPath::LangItem(..)) => succ,
|
||||||
|
|
||||||
// Note that labels have been resolved, so we don't need to look
|
// Note that labels have been resolved, so we don't need to look
|
||||||
// at the label ident
|
// at the label ident
|
||||||
|
|
|
@ -1325,7 +1325,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
||||||
Res::Def(kind, def_id) => Some((kind, def_id)),
|
Res::Def(kind, def_id) => Some((kind, def_id)),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
hir::QPath::TypeRelative(..) => self
|
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
|
||||||
.maybe_typeck_results
|
.maybe_typeck_results
|
||||||
.and_then(|typeck_results| typeck_results.type_dependent_def(id)),
|
.and_then(|typeck_results| typeck_results.type_dependent_def(id)),
|
||||||
};
|
};
|
||||||
|
@ -1340,7 +1340,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
||||||
let sess = self.tcx.sess;
|
let sess = self.tcx.sess;
|
||||||
let sm = sess.source_map();
|
let sm = sess.source_map();
|
||||||
let name = match qpath {
|
let name = match qpath {
|
||||||
hir::QPath::Resolved(_, path) => sm.span_to_snippet(path.span).ok(),
|
hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => {
|
||||||
|
sm.span_to_snippet(qpath.span()).ok()
|
||||||
|
}
|
||||||
hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
|
hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
|
||||||
};
|
};
|
||||||
let kind = kind.descr(def_id);
|
let kind = kind.descr(def_id);
|
||||||
|
|
|
@ -941,6 +941,24 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) {
|
||||||
|
match bound {
|
||||||
|
hir::GenericBound::LangItemTrait { .. } if !self.trait_ref_hack => {
|
||||||
|
let scope = Scope::Binder {
|
||||||
|
lifetimes: FxHashMap::default(),
|
||||||
|
s: self.scope,
|
||||||
|
next_early_index: self.next_early_index(),
|
||||||
|
track_lifetime_uses: true,
|
||||||
|
opaque_type_parent: false,
|
||||||
|
};
|
||||||
|
self.with(scope, |_, this| {
|
||||||
|
intravisit::walk_param_bound(this, bound);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => intravisit::walk_param_bound(self, bound),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_poly_trait_ref(
|
fn visit_poly_trait_ref(
|
||||||
&mut self,
|
&mut self,
|
||||||
trait_ref: &'tcx hir::PolyTraitRef<'tcx>,
|
trait_ref: &'tcx hir::PolyTraitRef<'tcx>,
|
||||||
|
@ -2296,6 +2314,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
self.outer_index.shift_out(1);
|
self.outer_index.shift_out(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_param_bound(&mut self, bound: &hir::GenericBound<'_>) {
|
||||||
|
if let hir::GenericBound::LangItemTrait { .. } = bound {
|
||||||
|
self.outer_index.shift_in(1);
|
||||||
|
intravisit::walk_param_bound(self, bound);
|
||||||
|
self.outer_index.shift_out(1);
|
||||||
|
} else {
|
||||||
|
intravisit::walk_param_bound(self, bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
|
fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
|
||||||
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
|
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
|
||||||
match lifetime {
|
match lifetime {
|
||||||
|
|
|
@ -1076,37 +1076,6 @@ impl ResolverAstLowering for Resolver<'_> {
|
||||||
self.cstore().item_generics_num_lifetimes(def_id, sess)
|
self.cstore().item_generics_num_lifetimes(def_id, sess)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_str_path(
|
|
||||||
&mut self,
|
|
||||||
span: Span,
|
|
||||||
crate_root: Option<Symbol>,
|
|
||||||
components: &[Symbol],
|
|
||||||
ns: Namespace,
|
|
||||||
) -> (ast::Path, Res) {
|
|
||||||
let root = if crate_root.is_some() { kw::PathRoot } else { kw::Crate };
|
|
||||||
let segments = iter::once(Ident::with_dummy_span(root))
|
|
||||||
.chain(
|
|
||||||
crate_root
|
|
||||||
.into_iter()
|
|
||||||
.chain(components.iter().cloned())
|
|
||||||
.map(Ident::with_dummy_span),
|
|
||||||
)
|
|
||||||
.map(|i| self.new_ast_path_segment(i))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let path = ast::Path { span, segments };
|
|
||||||
|
|
||||||
let parent_scope = &ParentScope::module(self.graph_root);
|
|
||||||
let res = match self.resolve_ast_path(&path, ns, parent_scope) {
|
|
||||||
Ok(res) => res,
|
|
||||||
Err((span, error)) => {
|
|
||||||
self.report_error(span, error);
|
|
||||||
Res::Err
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(path, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes> {
|
fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes> {
|
||||||
self.partial_res_map.get(&id).cloned()
|
self.partial_res_map.get(&id).cloned()
|
||||||
}
|
}
|
||||||
|
|
|
@ -702,14 +702,18 @@ impl<'tcx> DumpVisitor<'tcx> {
|
||||||
|
|
||||||
// super-traits
|
// super-traits
|
||||||
for super_bound in trait_refs.iter() {
|
for super_bound in trait_refs.iter() {
|
||||||
let trait_ref = match *super_bound {
|
let (def_id, sub_span) = match *super_bound {
|
||||||
hir::GenericBound::Trait(ref trait_ref, _) => trait_ref,
|
hir::GenericBound::Trait(ref trait_ref, _) => (
|
||||||
|
self.lookup_def_id(trait_ref.trait_ref.hir_ref_id),
|
||||||
|
trait_ref.trait_ref.path.segments.last().unwrap().ident.span,
|
||||||
|
),
|
||||||
|
hir::GenericBound::LangItemTrait(lang_item, span, _, _) => {
|
||||||
|
(Some(self.tcx.require_lang_item(lang_item, Some(span))), span)
|
||||||
|
}
|
||||||
hir::GenericBound::Outlives(..) => continue,
|
hir::GenericBound::Outlives(..) => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
let trait_ref = &trait_ref.trait_ref;
|
if let Some(id) = def_id {
|
||||||
if let Some(id) = self.lookup_def_id(trait_ref.hir_ref_id) {
|
|
||||||
let sub_span = trait_ref.path.segments.last().unwrap().ident.span;
|
|
||||||
if !self.span.filter_generated(sub_span) {
|
if !self.span.filter_generated(sub_span) {
|
||||||
let span = self.span_from_span(sub_span);
|
let span = self.span_from_span(sub_span);
|
||||||
self.dumper.dump_ref(Ref {
|
self.dumper.dump_ref(Ref {
|
||||||
|
@ -762,11 +766,7 @@ impl<'tcx> DumpVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_path(&mut self, id: hir::HirId, path: &hir::QPath<'tcx>) {
|
fn process_path(&mut self, id: hir::HirId, path: &hir::QPath<'tcx>) {
|
||||||
let span = match path {
|
if self.span.filter_generated(path.span()) {
|
||||||
hir::QPath::Resolved(_, path) => path.span,
|
|
||||||
hir::QPath::TypeRelative(_, segment) => segment.ident.span,
|
|
||||||
};
|
|
||||||
if self.span.filter_generated(span) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.dump_path_ref(id, path);
|
self.dump_path_ref(id, path);
|
||||||
|
@ -783,6 +783,7 @@ impl<'tcx> DumpVisitor<'tcx> {
|
||||||
self.visit_ty(ty);
|
self.visit_ty(ty);
|
||||||
std::slice::from_ref(*segment)
|
std::slice::from_ref(*segment)
|
||||||
}
|
}
|
||||||
|
hir::QPath::LangItem(..) => return,
|
||||||
};
|
};
|
||||||
for seg in segments {
|
for seg in segments {
|
||||||
if let Some(ref generic_args) = seg.args {
|
if let Some(ref generic_args) = seg.args {
|
||||||
|
@ -1355,10 +1356,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(id) = self.lookup_def_id(t.hir_id) {
|
if let Some(id) = self.lookup_def_id(t.hir_id) {
|
||||||
let sub_span = match path {
|
let sub_span = path.last_segment_span();
|
||||||
hir::QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span,
|
|
||||||
hir::QPath::TypeRelative(_, segment) => segment.ident.span,
|
|
||||||
};
|
|
||||||
let span = self.span_from_span(sub_span);
|
let span = self.span_from_span(sub_span);
|
||||||
self.dumper.dump_ref(Ref {
|
self.dumper.dump_ref(Ref {
|
||||||
kind: RefKind::Type,
|
kind: RefKind::Type,
|
||||||
|
|
|
@ -551,28 +551,22 @@ impl<'tcx> SaveContext<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ExprKind::Struct(qpath, ..) => {
|
hir::ExprKind::Struct(qpath, ..) => match ty.kind {
|
||||||
let segment = match qpath {
|
ty::Adt(def, _) => {
|
||||||
hir::QPath::Resolved(_, path) => path.segments.last().unwrap(),
|
let sub_span = qpath.last_segment_span();
|
||||||
hir::QPath::TypeRelative(_, segment) => segment,
|
filter!(self.span_utils, sub_span);
|
||||||
};
|
let span = self.span_from_span(sub_span);
|
||||||
match ty.kind {
|
Some(Data::RefData(Ref {
|
||||||
ty::Adt(def, _) => {
|
kind: RefKind::Type,
|
||||||
let sub_span = segment.ident.span;
|
span,
|
||||||
filter!(self.span_utils, sub_span);
|
ref_id: id_from_def_id(def.did),
|
||||||
let span = self.span_from_span(sub_span);
|
}))
|
||||||
Some(Data::RefData(Ref {
|
|
||||||
kind: RefKind::Type,
|
|
||||||
span,
|
|
||||||
ref_id: id_from_def_id(def.did),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
debug!("expected adt, found {:?}", ty);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
_ => {
|
||||||
|
debug!("expected adt, found {:?}", ty);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
hir::ExprKind::MethodCall(ref seg, ..) => {
|
hir::ExprKind::MethodCall(ref seg, ..) => {
|
||||||
let method_id = match self.typeck_results().type_dependent_def_id(expr.hir_id) {
|
let method_id = match self.typeck_results().type_dependent_def_id(expr.hir_id) {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
|
@ -636,7 +630,7 @@ impl<'tcx> SaveContext<'tcx> {
|
||||||
})
|
})
|
||||||
| Node::Ty(&hir::Ty { kind: hir::TyKind::Path(ref qpath), .. }) => match qpath {
|
| Node::Ty(&hir::Ty { kind: hir::TyKind::Path(ref qpath), .. }) => match qpath {
|
||||||
hir::QPath::Resolved(_, path) => path.res,
|
hir::QPath::Resolved(_, path) => path.res,
|
||||||
hir::QPath::TypeRelative(..) => self
|
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
|
||||||
.maybe_typeck_results
|
.maybe_typeck_results
|
||||||
.map_or(Res::Err, |typeck_results| typeck_results.qpath_res(qpath, hir_id)),
|
.map_or(Res::Err, |typeck_results| typeck_results.qpath_res(qpath, hir_id)),
|
||||||
},
|
},
|
||||||
|
@ -653,6 +647,7 @@ impl<'tcx> SaveContext<'tcx> {
|
||||||
let segment = match path {
|
let segment = match path {
|
||||||
hir::QPath::Resolved(_, path) => path.segments.last(),
|
hir::QPath::Resolved(_, path) => path.segments.last(),
|
||||||
hir::QPath::TypeRelative(_, segment) => Some(*segment),
|
hir::QPath::TypeRelative(_, segment) => Some(*segment),
|
||||||
|
hir::QPath::LangItem(..) => None,
|
||||||
};
|
};
|
||||||
segment.and_then(|seg| {
|
segment.and_then(|seg| {
|
||||||
self.get_path_segment_data(seg).or_else(|| self.get_path_segment_data_with_id(seg, id))
|
self.get_path_segment_data(seg).or_else(|| self.get_path_segment_data_with_id(seg, id))
|
||||||
|
|
|
@ -286,6 +286,9 @@ impl<'hir> Sig for hir::Ty<'hir> {
|
||||||
refs: vec![SigElement { id, start, end }],
|
refs: vec![SigElement { id, start, end }],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
hir::TyKind::Path(hir::QPath::LangItem(lang_item, _)) => {
|
||||||
|
Ok(text_sig(format!("#[lang = \"{}\"]", lang_item.name())))
|
||||||
|
}
|
||||||
hir::TyKind::TraitObject(bounds, ..) => {
|
hir::TyKind::TraitObject(bounds, ..) => {
|
||||||
// FIXME recurse into bounds
|
// FIXME recurse into bounds
|
||||||
let bounds: Vec<hir::GenericBound<'_>> = bounds
|
let bounds: Vec<hir::GenericBound<'_>> = bounds
|
||||||
|
|
|
@ -706,6 +706,7 @@ symbols! {
|
||||||
never_type,
|
never_type,
|
||||||
never_type_fallback,
|
never_type_fallback,
|
||||||
new,
|
new,
|
||||||
|
new_unchecked,
|
||||||
next,
|
next,
|
||||||
nll,
|
nll,
|
||||||
no,
|
no,
|
||||||
|
@ -828,6 +829,7 @@ symbols! {
|
||||||
quad_precision_float,
|
quad_precision_float,
|
||||||
question_mark,
|
question_mark,
|
||||||
quote,
|
quote,
|
||||||
|
range_inclusive_new,
|
||||||
raw_dylib,
|
raw_dylib,
|
||||||
raw_identifiers,
|
raw_identifiers,
|
||||||
raw_ref_op,
|
raw_ref_op,
|
||||||
|
|
|
@ -1202,6 +1202,36 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn instantiate_lang_item_trait_ref(
|
||||||
|
&self,
|
||||||
|
lang_item: hir::LangItem,
|
||||||
|
span: Span,
|
||||||
|
hir_id: hir::HirId,
|
||||||
|
args: &GenericArgs<'_>,
|
||||||
|
self_ty: Ty<'tcx>,
|
||||||
|
bounds: &mut Bounds<'tcx>,
|
||||||
|
) {
|
||||||
|
let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span));
|
||||||
|
|
||||||
|
let (substs, assoc_bindings, _) =
|
||||||
|
self.create_substs_for_ast_path(span, trait_def_id, &[], args, false, Some(self_ty));
|
||||||
|
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
|
||||||
|
bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst));
|
||||||
|
|
||||||
|
let mut dup_bindings = FxHashMap::default();
|
||||||
|
for binding in assoc_bindings {
|
||||||
|
let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding(
|
||||||
|
hir_id,
|
||||||
|
poly_trait_ref,
|
||||||
|
&binding,
|
||||||
|
bounds,
|
||||||
|
false,
|
||||||
|
&mut dup_bindings,
|
||||||
|
span,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn ast_path_to_mono_trait_ref(
|
fn ast_path_to_mono_trait_ref(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -1392,6 +1422,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
trait_bounds.push((b, Constness::NotConst))
|
trait_bounds.push((b, Constness::NotConst))
|
||||||
}
|
}
|
||||||
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
|
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
|
||||||
|
hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self
|
||||||
|
.instantiate_lang_item_trait_ref(
|
||||||
|
lang_item, span, hir_id, args, param_ty, bounds,
|
||||||
|
),
|
||||||
hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
|
hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2960,6 +2994,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
.map(|(ty, _, _)| ty)
|
.map(|(ty, _, _)| ty)
|
||||||
.unwrap_or_else(|_| tcx.ty_error())
|
.unwrap_or_else(|_| tcx.ty_error())
|
||||||
}
|
}
|
||||||
|
hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
|
||||||
|
let def_id = tcx.require_lang_item(lang_item, Some(span));
|
||||||
|
let (substs, _, _) = self.create_substs_for_ast_path(
|
||||||
|
span,
|
||||||
|
def_id,
|
||||||
|
&[],
|
||||||
|
&GenericArgs::none(),
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs))
|
||||||
|
}
|
||||||
hir::TyKind::Array(ref ty, ref length) => {
|
hir::TyKind::Array(ref ty, ref length) => {
|
||||||
let length_def_id = tcx.hir().local_def_id(length.hir_id);
|
let length_def_id = tcx.hir().local_def_id(length.hir_id);
|
||||||
let length = ty::Const::from_anon_const(tcx, length_def_id);
|
let length = ty::Const::from_anon_const(tcx, length_def_id);
|
||||||
|
|
|
@ -485,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// parenthesize if needed (Issue #46756)
|
// parenthesize if needed (Issue #46756)
|
||||||
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
|
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
|
||||||
// parenthesize borrows of range literals (Issue #54505)
|
// parenthesize borrows of range literals (Issue #54505)
|
||||||
_ if is_range_literal(self.tcx.sess.source_map(), expr) => true,
|
_ if is_range_literal(expr) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
let sugg_expr = if needs_parens { format!("({})", src) } else { src };
|
let sugg_expr = if needs_parens { format!("({})", src) } else { src };
|
||||||
|
|
|
@ -236,6 +236,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
ExprKind::AddrOf(kind, mutbl, ref oprnd) => {
|
ExprKind::AddrOf(kind, mutbl, ref oprnd) => {
|
||||||
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
|
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
|
||||||
}
|
}
|
||||||
|
ExprKind::Path(QPath::LangItem(lang_item, _)) => {
|
||||||
|
self.check_lang_item_path(lang_item, expr)
|
||||||
|
}
|
||||||
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr),
|
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr),
|
||||||
ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
|
ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
|
||||||
ExprKind::LlvmInlineAsm(ref asm) => {
|
ExprKind::LlvmInlineAsm(ref asm) => {
|
||||||
|
@ -447,6 +450,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_lang_item_path(
|
||||||
|
&self,
|
||||||
|
lang_item: hir::LangItem,
|
||||||
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1
|
||||||
|
}
|
||||||
|
|
||||||
fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
|
fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span);
|
let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span);
|
||||||
|
@ -1077,11 +1088,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
return self.tcx.ty_error();
|
return self.tcx.ty_error();
|
||||||
};
|
};
|
||||||
|
|
||||||
let path_span = match *qpath {
|
|
||||||
QPath::Resolved(_, ref path) => path.span,
|
|
||||||
QPath::TypeRelative(ref qself, _) => qself.span,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Prohibit struct expressions when non-exhaustive flag is set.
|
// Prohibit struct expressions when non-exhaustive flag is set.
|
||||||
let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type");
|
let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type");
|
||||||
if !adt.did.is_local() && variant.is_field_list_non_exhaustive() {
|
if !adt.did.is_local() && variant.is_field_list_non_exhaustive() {
|
||||||
|
@ -1099,7 +1105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
adt_ty,
|
adt_ty,
|
||||||
expected,
|
expected,
|
||||||
expr.hir_id,
|
expr.hir_id,
|
||||||
path_span,
|
qpath.span(),
|
||||||
variant,
|
variant,
|
||||||
fields,
|
fields,
|
||||||
base_expr.is_none(),
|
base_expr.is_none(),
|
||||||
|
|
|
@ -122,10 +122,9 @@ use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
|
use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
|
||||||
use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts};
|
use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts};
|
||||||
use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
|
use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::WithConstness;
|
||||||
self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef,
|
use rustc_middle::ty::{self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind};
|
||||||
ToPredicate, Ty, TyCtxt, UserType, WithConstness,
|
use rustc_middle::ty::{RegionKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType};
|
||||||
};
|
|
||||||
use rustc_session::config::{self, EntryFnType};
|
use rustc_session::config::{self, EntryFnType};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_session::parse::feature_err;
|
use rustc_session::parse::feature_err;
|
||||||
|
@ -4430,10 +4429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
qpath: &QPath<'_>,
|
qpath: &QPath<'_>,
|
||||||
hir_id: hir::HirId,
|
hir_id: hir::HirId,
|
||||||
) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> {
|
) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> {
|
||||||
let path_span = match *qpath {
|
let path_span = qpath.qself_span();
|
||||||
QPath::Resolved(_, ref path) => path.span,
|
|
||||||
QPath::TypeRelative(ref qself, _) => qself.span,
|
|
||||||
};
|
|
||||||
let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
|
let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
|
||||||
let variant = match def {
|
let variant = match def {
|
||||||
Res::Err => {
|
Res::Err => {
|
||||||
|
@ -4511,9 +4507,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
(result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty)
|
(result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty)
|
||||||
}
|
}
|
||||||
|
QPath::LangItem(lang_item, span) => {
|
||||||
|
self.resolve_lang_item_path(lang_item, span, hir_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_lang_item_path(
|
||||||
|
&self,
|
||||||
|
lang_item: hir::LangItem,
|
||||||
|
span: Span,
|
||||||
|
hir_id: hir::HirId,
|
||||||
|
) -> (Res, Ty<'tcx>) {
|
||||||
|
let def_id = self.tcx.require_lang_item(lang_item, Some(span));
|
||||||
|
let def_kind = self.tcx.def_kind(def_id);
|
||||||
|
|
||||||
|
let item_ty = if let DefKind::Variant = def_kind {
|
||||||
|
self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
|
||||||
|
} else {
|
||||||
|
self.tcx.type_of(def_id)
|
||||||
|
};
|
||||||
|
let substs = self.infcx.fresh_substs_for_item(span, def_id);
|
||||||
|
let ty = item_ty.subst(self.tcx, substs);
|
||||||
|
|
||||||
|
self.write_resolution(hir_id, Ok((def_kind, def_id)));
|
||||||
|
self.add_required_obligations(span, def_id, &substs);
|
||||||
|
(Res::Def(def_kind, def_id), ty)
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolves an associated value path into a base type and associated constant, or method
|
/// Resolves an associated value path into a base type and associated constant, or method
|
||||||
/// resolution. The newly resolved definition is written into `type_dependent_defs`.
|
/// resolution. The newly resolved definition is written into `type_dependent_defs`.
|
||||||
pub fn resolve_ty_and_res_ufcs<'b>(
|
pub fn resolve_ty_and_res_ufcs<'b>(
|
||||||
|
@ -4532,6 +4553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
|
QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
|
||||||
|
QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"),
|
||||||
};
|
};
|
||||||
if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
|
if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -947,13 +947,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// |
|
// |
|
||||||
// L | let A(()) = A(());
|
// L | let A(()) = A(());
|
||||||
// | ^ ^
|
// | ^ ^
|
||||||
[] => {
|
[] => (qpath.span().shrink_to_hi(), pat_span),
|
||||||
let qpath_span = match qpath {
|
|
||||||
hir::QPath::Resolved(_, path) => path.span,
|
|
||||||
hir::QPath::TypeRelative(_, ps) => ps.ident.span,
|
|
||||||
};
|
|
||||||
(qpath_span.shrink_to_hi(), pat_span)
|
|
||||||
}
|
|
||||||
// Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the
|
// Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the
|
||||||
// last sub-pattern. In the case of `A(x)` the first and last may coincide.
|
// last sub-pattern. In the case of `A(x)` the first and last may coincide.
|
||||||
// This looks like:
|
// This looks like:
|
||||||
|
|
|
@ -1959,6 +1959,20 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
|
||||||
predicates.extend(bounds.predicates(tcx, ty));
|
predicates.extend(bounds.predicates(tcx, ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
|
||||||
|
let mut bounds = Bounds::default();
|
||||||
|
AstConv::instantiate_lang_item_trait_ref(
|
||||||
|
&icx,
|
||||||
|
lang_item,
|
||||||
|
span,
|
||||||
|
hir_id,
|
||||||
|
args,
|
||||||
|
ty,
|
||||||
|
&mut bounds,
|
||||||
|
);
|
||||||
|
predicates.extend(bounds.predicates(tcx, ty));
|
||||||
|
}
|
||||||
|
|
||||||
&hir::GenericBound::Outlives(ref lifetime) => {
|
&hir::GenericBound::Outlives(ref lifetime) => {
|
||||||
let region = AstConv::ast_region_to_region(&icx, lifetime, None);
|
let region = AstConv::ast_region_to_region(&icx, lifetime, None);
|
||||||
predicates.push((
|
predicates.push((
|
||||||
|
@ -2108,6 +2122,18 @@ fn predicates_from_bound<'tcx>(
|
||||||
let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds);
|
let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds);
|
||||||
bounds.predicates(astconv.tcx(), param_ty)
|
bounds.predicates(astconv.tcx(), param_ty)
|
||||||
}
|
}
|
||||||
|
hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
|
||||||
|
let mut bounds = Bounds::default();
|
||||||
|
astconv.instantiate_lang_item_trait_ref(
|
||||||
|
lang_item,
|
||||||
|
span,
|
||||||
|
hir_id,
|
||||||
|
args,
|
||||||
|
param_ty,
|
||||||
|
&mut bounds,
|
||||||
|
);
|
||||||
|
bounds.predicates(astconv.tcx(), param_ty)
|
||||||
|
}
|
||||||
hir::GenericBound::Outlives(ref lifetime) => {
|
hir::GenericBound::Outlives(ref lifetime) => {
|
||||||
let region = astconv.ast_region_to_region(lifetime, None);
|
let region = astconv.ast_region_to_region(lifetime, None);
|
||||||
let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region))
|
let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region))
|
||||||
|
|
|
@ -17,6 +17,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||||
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
|
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
|
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||||
|
use rustc_middle::bug;
|
||||||
use rustc_middle::middle::resolve_lifetime as rl;
|
use rustc_middle::middle::resolve_lifetime as rl;
|
||||||
use rustc_middle::middle::stability;
|
use rustc_middle::middle::stability;
|
||||||
use rustc_middle::ty::fold::TypeFolder;
|
use rustc_middle::ty::fold::TypeFolder;
|
||||||
|
@ -291,6 +292,22 @@ impl Clean<GenericBound> for hir::GenericBound<'_> {
|
||||||
fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
|
fn clean(&self, cx: &DocContext<'_>) -> GenericBound {
|
||||||
match *self {
|
match *self {
|
||||||
hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
|
hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
|
||||||
|
hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
|
||||||
|
let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
|
||||||
|
|
||||||
|
let trait_ref = ty::TraitRef::identity(cx.tcx, def_id);
|
||||||
|
|
||||||
|
let generic_args = generic_args.clean(cx);
|
||||||
|
let bindings = match generic_args {
|
||||||
|
GenericArgs::AngleBracketed { bindings, .. } => bindings,
|
||||||
|
_ => bug!("clean: parenthesized `GenericBound::LangItemTrait`"),
|
||||||
|
};
|
||||||
|
|
||||||
|
GenericBound::TraitBound(
|
||||||
|
PolyTrait { trait_: (trait_ref, &*bindings).clean(cx), generic_params: vec![] },
|
||||||
|
hir::TraitBoundModifier::None,
|
||||||
|
)
|
||||||
|
}
|
||||||
hir::GenericBound::Trait(ref t, modifier) => {
|
hir::GenericBound::Trait(ref t, modifier) => {
|
||||||
GenericBound::TraitBound(t.clean(cx), modifier)
|
GenericBound::TraitBound(t.clean(cx), modifier)
|
||||||
}
|
}
|
||||||
|
@ -1504,6 +1521,9 @@ impl Clean<Type> for hir::Ty<'_> {
|
||||||
trait_: box resolve_type(cx, trait_path.clean(cx), self.hir_id),
|
trait_: box resolve_type(cx, trait_path.clean(cx), self.hir_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TyKind::Path(hir::QPath::LangItem(..)) => {
|
||||||
|
bug!("clean: requiring documentation of lang item")
|
||||||
|
}
|
||||||
TyKind::TraitObject(ref bounds, ref lifetime) => {
|
TyKind::TraitObject(ref bounds, ref lifetime) => {
|
||||||
match bounds[0].clean(cx).trait_ {
|
match bounds[0].clean(cx).trait_ {
|
||||||
ResolvedPath { path, param_names: None, did, is_generic } => {
|
ResolvedPath { path, param_names: None, did, is_generic } => {
|
||||||
|
|
|
@ -335,6 +335,7 @@ pub fn qpath_to_string(p: &hir::QPath<'_>) -> String {
|
||||||
let segments = match *p {
|
let segments = match *p {
|
||||||
hir::QPath::Resolved(_, ref path) => &path.segments,
|
hir::QPath::Resolved(_, ref path) => &path.segments,
|
||||||
hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
|
hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
|
||||||
|
hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
|
|
18
src/test/ui/hygiene/hir-res-hygiene.rs
Normal file
18
src/test/ui/hygiene/hir-res-hygiene.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// check-pass
|
||||||
|
// edition:2018
|
||||||
|
// aux-build:not-libstd.rs
|
||||||
|
|
||||||
|
// Check that paths created in HIR are not affected by in scope names.
|
||||||
|
|
||||||
|
extern crate not_libstd as std;
|
||||||
|
|
||||||
|
async fn the_future() {
|
||||||
|
async {}.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), ()> {
|
||||||
|
for i in 0..10 {}
|
||||||
|
for j in 0..=10 {}
|
||||||
|
Ok(())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -17,9 +17,13 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi
|
||||||
|
|
|
|
||||||
LL | let range = *arr..;
|
LL | let range = *arr..;
|
||||||
| ^^^^^^ doesn't have a size known at compile-time
|
| ^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
::: $SRC_DIR/core/src/ops/range.rs:LL:COL
|
||||||
|
|
|
||||||
|
LL | pub struct RangeFrom<Idx> {
|
||||||
|
| --- required by this bound in `std::ops::RangeFrom`
|
||||||
|
|
|
|
||||||
= help: the trait `std::marker::Sized` is not implemented for `[{integer}]`
|
= help: the trait `std::marker::Sized` is not implemented for `[{integer}]`
|
||||||
= note: required by `std::ops::RangeFrom`
|
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
QPath::TypeRelative(..) => {},
|
QPath::TypeRelative(..) | QPath::LangItem(..) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
if let ExprKind::Index(ref array, ref index) = &expr.kind {
|
if let ExprKind::Index(ref array, ref index) = &expr.kind {
|
||||||
let ty = cx.typeck_results().expr_ty(array);
|
let ty = cx.typeck_results().expr_ty(array);
|
||||||
if let Some(range) = higher::range(cx, index) {
|
if let Some(range) = higher::range(index) {
|
||||||
// Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
|
// Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
|
||||||
if let ty::Array(_, s) = ty.kind {
|
if let ty::Array(_, s) = ty.kind {
|
||||||
let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) {
|
let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) {
|
||||||
|
|
|
@ -171,7 +171,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
||||||
Finite
|
Finite
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ExprKind::Struct(..) => higher::range(cx, expr).map_or(false, |r| r.end.is_none()).into(),
|
ExprKind::Struct(..) => higher::range(expr).map_or(false, |r| r.end.is_none()).into(),
|
||||||
_ => Finite,
|
_ => Finite,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,7 @@ fn check_len(
|
||||||
fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
/// Special case ranges until `range_is_empty` is stabilized. See issue 3807.
|
/// Special case ranges until `range_is_empty` is stabilized. See issue 3807.
|
||||||
fn should_skip_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
fn should_skip_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
higher::range(cx, expr).map_or(false, |_| {
|
higher::range(expr).map_or(false, |_| {
|
||||||
!cx.tcx
|
!cx.tcx
|
||||||
.features()
|
.features()
|
||||||
.declared_lib_features
|
.declared_lib_features
|
||||||
|
|
|
@ -1003,7 +1003,7 @@ fn detect_manual_memcpy<'tcx>(
|
||||||
start: Some(start),
|
start: Some(start),
|
||||||
end: Some(end),
|
end: Some(end),
|
||||||
limits,
|
limits,
|
||||||
}) = higher::range(cx, arg)
|
}) = higher::range(arg)
|
||||||
{
|
{
|
||||||
// the var must be a single name
|
// the var must be a single name
|
||||||
if let PatKind::Binding(_, canonical_id, _, _) = pat.kind {
|
if let PatKind::Binding(_, canonical_id, _, _) = pat.kind {
|
||||||
|
@ -1177,7 +1177,7 @@ fn check_for_loop_range<'tcx>(
|
||||||
start: Some(start),
|
start: Some(start),
|
||||||
ref end,
|
ref end,
|
||||||
limits,
|
limits,
|
||||||
}) = higher::range(cx, arg)
|
}) = higher::range(arg)
|
||||||
{
|
{
|
||||||
// the var must be a single name
|
// the var must be a single name
|
||||||
if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind {
|
if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind {
|
||||||
|
@ -1679,7 +1679,7 @@ fn check_for_mut_range_bound(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'
|
||||||
start: Some(start),
|
start: Some(start),
|
||||||
end: Some(end),
|
end: Some(end),
|
||||||
..
|
..
|
||||||
}) = higher::range(cx, arg)
|
}) = higher::range(arg)
|
||||||
{
|
{
|
||||||
let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
|
let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
|
||||||
if mut_ids[0].is_some() || mut_ids[1].is_some() {
|
if mut_ids[0].is_some() || mut_ids[1].is_some() {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::utils::{self, is_type_diagnostic_item, match_type, snippet, span_lint_and_sugg, walk_ptrs_ty};
|
use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg};
|
||||||
|
use crate::utils::walk_ptrs_ty;
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, ExprKind, MatchSource};
|
use rustc_hir::{Expr, ExprKind, LangItem, MatchSource};
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
|
@ -96,5 +97,5 @@ fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
let ty = cx.typeck_results().expr_ty(expr);
|
let ty = cx.typeck_results().expr_ty(expr);
|
||||||
let ty = walk_ptrs_ty(ty);
|
let ty = walk_ptrs_ty(ty);
|
||||||
match_type(cx, ty, &utils::paths::RANGE_FULL)
|
is_type_lang_item(cx, ty, LangItem::RangeFull)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2271,7 +2271,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
|
if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
|
||||||
if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
|
if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
|
||||||
= higher::range(cx, index_expr);
|
= higher::range(index_expr);
|
||||||
if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
|
if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
|
||||||
if let ast::LitKind::Int(start_idx, _) = start_lit.node;
|
if let ast::LitKind::Int(start_idx, _) = start_lit.node;
|
||||||
then {
|
then {
|
||||||
|
|
|
@ -433,6 +433,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let binding = match expr.kind {
|
let binding = match expr.kind {
|
||||||
|
ExprKind::Path(hir::QPath::LangItem(..)) => None,
|
||||||
ExprKind::Path(ref qpath) => {
|
ExprKind::Path(ref qpath) => {
|
||||||
let binding = last_path_segment(qpath).ident.as_str();
|
let binding = last_path_segment(qpath).ident.as_str();
|
||||||
if binding.starts_with('_') &&
|
if binding.starts_with('_') &&
|
||||||
|
|
|
@ -147,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
|
||||||
if let ExprKind::MethodCall(ref iter_path, _, ref iter_args , _) = *iter;
|
if let ExprKind::MethodCall(ref iter_path, _, ref iter_args , _) = *iter;
|
||||||
if iter_path.ident.name == sym!(iter);
|
if iter_path.ident.name == sym!(iter);
|
||||||
// range expression in `.zip()` call: `0..x.len()`
|
// range expression in `.zip()` call: `0..x.len()`
|
||||||
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(cx, zip_arg);
|
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg);
|
||||||
if is_integer_const(cx, start, 0);
|
if is_integer_const(cx, start, 0);
|
||||||
// `.len()` call
|
// `.len()` call
|
||||||
if let ExprKind::MethodCall(ref len_path, _, ref len_args, _) = end.kind;
|
if let ExprKind::MethodCall(ref len_path, _, ref len_args, _) = end.kind;
|
||||||
|
@ -180,7 +180,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
start,
|
start,
|
||||||
end: Some(end),
|
end: Some(end),
|
||||||
limits: RangeLimits::HalfOpen
|
limits: RangeLimits::HalfOpen
|
||||||
}) = higher::range(cx, expr);
|
}) = higher::range(expr);
|
||||||
if let Some(y) = y_plus_one(cx, end);
|
if let Some(y) = y_plus_one(cx, end);
|
||||||
then {
|
then {
|
||||||
let span = if expr.span.from_expansion() {
|
let span = if expr.span.from_expansion() {
|
||||||
|
@ -225,7 +225,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
// inclusive range minus one: `x..=(y-1)`
|
// inclusive range minus one: `x..=(y-1)`
|
||||||
fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(cx, expr);
|
if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(expr);
|
||||||
if let Some(y) = y_minus_one(cx, end);
|
if let Some(y) = y_minus_one(cx, end);
|
||||||
then {
|
then {
|
||||||
span_lint_and_then(
|
span_lint_and_then(
|
||||||
|
@ -279,7 +279,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(cx, expr);
|
if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(expr);
|
||||||
let ty = cx.typeck_results().expr_ty(start);
|
let ty = cx.typeck_results().expr_ty(start);
|
||||||
if let ty::Int(_) | ty::Uint(_) = ty.kind;
|
if let ty::Int(_) | ty::Uint(_) = ty.kind;
|
||||||
if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start);
|
if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite,
|
is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet,
|
||||||
span_lint_and_sugg,
|
snippet_with_macro_callsite, span_lint_and_sugg,
|
||||||
};
|
};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, ExprKind, MatchSource};
|
use rustc_hir::{Expr, ExprKind, QPath, LangItem, MatchSource};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_middle::ty::{self, Ty};
|
use rustc_middle::ty::{self, Ty};
|
||||||
|
@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
|
||||||
if let ExprKind::Match(ref match_arg, _, MatchSource::TryDesugar) = expr.kind;
|
if let ExprKind::Match(ref match_arg, _, MatchSource::TryDesugar) = expr.kind;
|
||||||
if let ExprKind::Call(ref match_fun, ref try_args) = match_arg.kind;
|
if let ExprKind::Call(ref match_fun, ref try_args) = match_arg.kind;
|
||||||
if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
|
if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
|
||||||
if match_qpath(match_fun_path, &paths::TRY_INTO_RESULT);
|
if matches!(match_fun_path, QPath::LangItem(LangItem::TryIntoResult, _));
|
||||||
if let Some(ref try_arg) = try_args.get(0);
|
if let Some(ref try_arg) = try_args.get(0);
|
||||||
if let ExprKind::Call(ref err_fun, ref err_args) = try_arg.kind;
|
if let ExprKind::Call(ref err_fun, ref err_args) = try_arg.kind;
|
||||||
if let Some(ref err_arg) = err_args.get(0);
|
if let Some(ref err_arg) = err_args.get(0);
|
||||||
|
|
|
@ -475,6 +475,7 @@ impl Types {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
QPath::LangItem(..) => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TyKind::Rptr(ref lt, ref mut_ty) => self.check_ty_rptr(cx, hir_ty, is_local, lt, mut_ty),
|
TyKind::Rptr(ref lt, ref mut_ty) => self.check_ty_rptr(cx, hir_ty, is_local, lt, mut_ty),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::utils::{is_try, match_qpath, match_trait_method, paths, span_lint};
|
use crate::utils::{is_try, match_trait_method, paths, span_lint};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
|
@ -42,10 +42,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
hir::ExprKind::Match(ref res, _, _) if is_try(expr).is_some() => {
|
hir::ExprKind::Match(ref res, _, _) if is_try(expr).is_some() => {
|
||||||
if let hir::ExprKind::Call(ref func, ref args) = res.kind {
|
if let hir::ExprKind::Call(ref func, ref args) = res.kind {
|
||||||
if let hir::ExprKind::Path(ref path) = func.kind {
|
if matches!(
|
||||||
if match_qpath(path, &paths::TRY_INTO_RESULT) && args.len() == 1 {
|
func.kind,
|
||||||
check_method_call(cx, &args[0], expr);
|
hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryIntoResult, _))
|
||||||
}
|
) {
|
||||||
|
check_method_call(cx, &args[0], expr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
check_method_call(cx, res, expr);
|
check_method_call(cx, res, expr);
|
||||||
|
|
|
@ -175,9 +175,19 @@ impl PrintVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_qpath(&mut self, path: &QPath<'_>) {
|
fn print_qpath(&mut self, path: &QPath<'_>) {
|
||||||
print!(" if match_qpath({}, &[", self.current);
|
match *path {
|
||||||
print_path(path, &mut true);
|
QPath::LangItem(lang_item, _) => {
|
||||||
println!("]);");
|
println!(
|
||||||
|
" if matches!({}, QPath::LangItem(LangItem::{:?}, _));",
|
||||||
|
self.current, lang_item,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
print!(" if match_qpath({}, &[", self.current);
|
||||||
|
print_path(path, &mut true);
|
||||||
|
println!("]);");
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -760,5 +770,6 @@ fn print_path(path: &QPath<'_>, first: &mut bool) {
|
||||||
},
|
},
|
||||||
ref other => print!("/* unimplemented: {:?}*/", other),
|
ref other => print!("/* unimplemented: {:?}*/", other),
|
||||||
},
|
},
|
||||||
|
QPath::LangItem(..) => panic!("print_path: called for lang item qpath"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,11 @@
|
||||||
|
|
||||||
#![deny(clippy::missing_docs_in_private_items)]
|
#![deny(clippy::missing_docs_in_private_items)]
|
||||||
|
|
||||||
use crate::utils::{is_expn_of, match_def_path, match_qpath, paths};
|
use crate::utils::{is_expn_of, match_def_path, paths};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty;
|
|
||||||
|
|
||||||
/// Converts a hir binary operator to the corresponding `ast` type.
|
/// Converts a hir binary operator to the corresponding `ast` type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -47,7 +46,7 @@ pub struct Range<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
|
/// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
|
||||||
pub fn range<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
|
pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
|
||||||
/// Finds the field named `name` in the field. Always return `Some` for
|
/// Finds the field named `name` in the field. Always return `Some` for
|
||||||
/// convenience.
|
/// convenience.
|
||||||
fn get_field<'c>(name: &str, fields: &'c [hir::Field<'_>]) -> Option<&'c hir::Expr<'c>> {
|
fn get_field<'c>(name: &str, fields: &'c [hir::Field<'_>]) -> Option<&'c hir::Expr<'c>> {
|
||||||
|
@ -56,94 +55,43 @@ pub fn range<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a hir::Expr<'_>) -> Optio
|
||||||
Some(expr)
|
Some(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
let def_path = match cx.typeck_results().expr_ty(expr).kind {
|
|
||||||
ty::Adt(def, _) => cx.tcx.def_path(def.did),
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// sanity checks for std::ops::RangeXXXX
|
|
||||||
if def_path.data.len() != 3 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if def_path.data.get(0)?.data.as_symbol() != sym!(ops) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
if def_path.data.get(1)?.data.as_symbol() != sym!(range) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let type_name = def_path.data.get(2)?.data.as_symbol();
|
|
||||||
let range_types = [
|
|
||||||
"RangeFrom",
|
|
||||||
"RangeFull",
|
|
||||||
"RangeInclusive",
|
|
||||||
"Range",
|
|
||||||
"RangeTo",
|
|
||||||
"RangeToInclusive",
|
|
||||||
];
|
|
||||||
if !range_types.contains(&&*type_name.as_str()) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The range syntax is expanded to literal paths starting with `core` or `std`
|
|
||||||
// depending on
|
|
||||||
// `#[no_std]`. Testing both instead of resolving the paths.
|
|
||||||
|
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
hir::ExprKind::Path(ref path) => {
|
hir::ExprKind::Call(ref path, ref args) if matches!(
|
||||||
if match_qpath(path, &paths::RANGE_FULL_STD) || match_qpath(path, &paths::RANGE_FULL) {
|
path.kind,
|
||||||
Some(Range {
|
hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
|
||||||
|
) => Some(Range {
|
||||||
|
start: Some(&args[0]),
|
||||||
|
end: Some(&args[1]),
|
||||||
|
limits: ast::RangeLimits::Closed,
|
||||||
|
}),
|
||||||
|
hir::ExprKind::Struct(ref path, ref fields, None) => {
|
||||||
|
match path {
|
||||||
|
hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
|
||||||
start: None,
|
start: None,
|
||||||
end: None,
|
end: None,
|
||||||
limits: ast::RangeLimits::HalfOpen,
|
limits: ast::RangeLimits::HalfOpen,
|
||||||
})
|
}),
|
||||||
} else {
|
hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range {
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hir::ExprKind::Call(ref path, ref args) => {
|
|
||||||
if let hir::ExprKind::Path(ref path) = path.kind {
|
|
||||||
if match_qpath(path, &paths::RANGE_INCLUSIVE_STD_NEW) || match_qpath(path, &paths::RANGE_INCLUSIVE_NEW)
|
|
||||||
{
|
|
||||||
Some(Range {
|
|
||||||
start: Some(&args[0]),
|
|
||||||
end: Some(&args[1]),
|
|
||||||
limits: ast::RangeLimits::Closed,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hir::ExprKind::Struct(ref path, ref fields, None) => {
|
|
||||||
if match_qpath(path, &paths::RANGE_FROM_STD) || match_qpath(path, &paths::RANGE_FROM) {
|
|
||||||
Some(Range {
|
|
||||||
start: Some(get_field("start", fields)?),
|
start: Some(get_field("start", fields)?),
|
||||||
end: None,
|
end: None,
|
||||||
limits: ast::RangeLimits::HalfOpen,
|
limits: ast::RangeLimits::HalfOpen,
|
||||||
})
|
}),
|
||||||
} else if match_qpath(path, &paths::RANGE_STD) || match_qpath(path, &paths::RANGE) {
|
hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range {
|
||||||
Some(Range {
|
|
||||||
start: Some(get_field("start", fields)?),
|
start: Some(get_field("start", fields)?),
|
||||||
end: Some(get_field("end", fields)?),
|
end: Some(get_field("end", fields)?),
|
||||||
limits: ast::RangeLimits::HalfOpen,
|
limits: ast::RangeLimits::HalfOpen,
|
||||||
})
|
}),
|
||||||
} else if match_qpath(path, &paths::RANGE_TO_INCLUSIVE_STD) || match_qpath(path, &paths::RANGE_TO_INCLUSIVE)
|
hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range {
|
||||||
{
|
|
||||||
Some(Range {
|
|
||||||
start: None,
|
start: None,
|
||||||
end: Some(get_field("end", fields)?),
|
end: Some(get_field("end", fields)?),
|
||||||
limits: ast::RangeLimits::Closed,
|
limits: ast::RangeLimits::Closed,
|
||||||
})
|
}),
|
||||||
} else if match_qpath(path, &paths::RANGE_TO_STD) || match_qpath(path, &paths::RANGE_TO) {
|
hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range {
|
||||||
Some(Range {
|
|
||||||
start: None,
|
start: None,
|
||||||
end: Some(get_field("end", fields)?),
|
end: Some(get_field("end", fields)?),
|
||||||
limits: ast::RangeLimits::HalfOpen,
|
limits: ast::RangeLimits::HalfOpen,
|
||||||
})
|
}),
|
||||||
} else {
|
_ => None,
|
||||||
None
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
@ -3,9 +3,9 @@ use crate::utils::differing_macro_contexts;
|
||||||
use rustc_ast::ast::InlineAsmTemplatePiece;
|
use rustc_ast::ast::InlineAsmTemplatePiece;
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FnRetTy, GenericArg,
|
BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FieldPat,
|
||||||
GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path, PathSegment, QPath,
|
FnRetTy, GenericArg, GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName,
|
||||||
Stmt, StmtKind, Ty, TyKind, TypeBinding,
|
Pat, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
|
||||||
};
|
};
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ich::StableHashingContextProvider;
|
use rustc_middle::ich::StableHashingContextProvider;
|
||||||
|
@ -185,10 +185,20 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
left.name == right.name
|
left.name == right.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn eq_fieldpat(&mut self, left: &FieldPat<'_>, right: &FieldPat<'_>) -> bool {
|
||||||
|
match (&left, &right) {
|
||||||
|
(FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) =>
|
||||||
|
li.name.as_str() == ri.name.as_str() && self.eq_pat(lp, rp),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks whether two patterns are the same.
|
/// Checks whether two patterns are the same.
|
||||||
pub fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
|
pub fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
|
||||||
match (&left.kind, &right.kind) {
|
match (&left.kind, &right.kind) {
|
||||||
(&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
|
(&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
|
||||||
|
(&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => {
|
||||||
|
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_fieldpat(l, r))
|
||||||
|
},
|
||||||
(&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
|
(&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
|
||||||
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
|
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
|
||||||
},
|
},
|
||||||
|
@ -223,6 +233,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||||
(&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
|
(&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
|
||||||
self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
|
self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
|
||||||
},
|
},
|
||||||
|
(&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) =>
|
||||||
|
llang_item == rlang_item,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -601,6 +613,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||||
QPath::TypeRelative(_, ref path) => {
|
QPath::TypeRelative(_, ref path) => {
|
||||||
self.hash_name(path.ident.name);
|
self.hash_name(path.ident.name);
|
||||||
},
|
},
|
||||||
|
QPath::LangItem(lang_item, ..) => {
|
||||||
|
lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
|
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
|
||||||
}
|
}
|
||||||
|
@ -710,6 +725,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||||
self.hash_ty(ty);
|
self.hash_ty(ty);
|
||||||
segment.ident.name.hash(&mut self.s);
|
segment.ident.name.hash(&mut self.s);
|
||||||
},
|
},
|
||||||
|
QPath::LangItem(lang_item, ..) => {
|
||||||
|
lang_item.hash(&mut self.s);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
TyKind::OpaqueDef(_, arg_list) => {
|
TyKind::OpaqueDef(_, arg_list) => {
|
||||||
self.hash_generic_args(arg_list);
|
self.hash_generic_args(arg_list);
|
||||||
|
|
|
@ -266,6 +266,9 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
|
||||||
println!("{}Relative Path, {:?}", ind, ty);
|
println!("{}Relative Path, {:?}", ind, ty);
|
||||||
println!("{}seg: {:?}", ind, seg);
|
println!("{}seg: {:?}", ind, seg);
|
||||||
},
|
},
|
||||||
|
hir::ExprKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
|
||||||
|
println!("{}Lang Item Path, {:?}", ind, lang_item.name());
|
||||||
|
},
|
||||||
hir::ExprKind::AddrOf(kind, ref muta, ref e) => {
|
hir::ExprKind::AddrOf(kind, ref muta, ref e) => {
|
||||||
println!("{}AddrOf", ind);
|
println!("{}AddrOf", ind);
|
||||||
println!("kind: {:?}", kind);
|
println!("kind: {:?}", kind);
|
||||||
|
@ -488,6 +491,9 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
|
||||||
println!("{}Relative Path, {:?}", ind, ty);
|
println!("{}Relative Path, {:?}", ind, ty);
|
||||||
println!("{}seg: {:?}", ind, seg);
|
println!("{}seg: {:?}", ind, seg);
|
||||||
},
|
},
|
||||||
|
hir::PatKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
|
||||||
|
println!("{}Lang Item Path, {:?}", ind, lang_item.name());
|
||||||
|
},
|
||||||
hir::PatKind::Tuple(pats, opt_dots_position) => {
|
hir::PatKind::Tuple(pats, opt_dots_position) => {
|
||||||
println!("{}Tuple", ind);
|
println!("{}Tuple", ind);
|
||||||
if let Some(dot_position) = opt_dots_position {
|
if let Some(dot_position) = opt_dots_position {
|
||||||
|
|
|
@ -142,6 +142,14 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if the type is equal to a lang item
|
||||||
|
pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
|
||||||
|
match ty.kind {
|
||||||
|
ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).unwrap() == adt.did,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if the method call given in `expr` belongs to the given trait.
|
/// Checks if the method call given in `expr` belongs to the given trait.
|
||||||
pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
|
pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
|
||||||
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
|
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
|
||||||
|
@ -163,6 +171,7 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
|
||||||
match *path {
|
match *path {
|
||||||
QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
|
QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
|
||||||
QPath::TypeRelative(_, ref seg) => seg,
|
QPath::TypeRelative(_, ref seg) => seg,
|
||||||
|
QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +179,7 @@ pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment
|
||||||
match *path {
|
match *path {
|
||||||
QPath::Resolved(_, ref path) => path.segments.get(0),
|
QPath::Resolved(_, ref path) => path.segments.get(0),
|
||||||
QPath::TypeRelative(_, ref seg) => Some(seg),
|
QPath::TypeRelative(_, ref seg) => Some(seg),
|
||||||
|
QPath::LangItem(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,6 +206,7 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
|
||||||
},
|
},
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
QPath::LangItem(..) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +288,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<def::Res> {
|
||||||
pub fn qpath_res(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
|
pub fn qpath_res(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
|
||||||
match qpath {
|
match qpath {
|
||||||
hir::QPath::Resolved(_, path) => path.res,
|
hir::QPath::Resolved(_, path) => path.res,
|
||||||
hir::QPath::TypeRelative(..) => {
|
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
|
||||||
if cx.tcx.has_typeck_results(id.owner.to_def_id()) {
|
if cx.tcx.has_typeck_results(id.owner.to_def_id()) {
|
||||||
cx.tcx.typeck(id.owner.to_def_id().expect_local()).qpath_res(qpath, id)
|
cx.tcx.typeck(id.owner.to_def_id().expect_local()).qpath_res(qpath, id)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -84,19 +84,7 @@ pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
|
||||||
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
|
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
|
||||||
pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
|
pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
|
||||||
pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
|
pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
|
||||||
pub const RANGE: [&str; 3] = ["core", "ops", "Range"];
|
|
||||||
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
|
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
|
||||||
pub const RANGE_FROM: [&str; 3] = ["core", "ops", "RangeFrom"];
|
|
||||||
pub const RANGE_FROM_STD: [&str; 3] = ["std", "ops", "RangeFrom"];
|
|
||||||
pub const RANGE_FULL: [&str; 4] = ["core", "ops", "range", "RangeFull"];
|
|
||||||
pub const RANGE_FULL_STD: [&str; 3] = ["std", "ops", "RangeFull"];
|
|
||||||
pub const RANGE_INCLUSIVE_NEW: [&str; 4] = ["core", "ops", "RangeInclusive", "new"];
|
|
||||||
pub const RANGE_INCLUSIVE_STD_NEW: [&str; 4] = ["std", "ops", "RangeInclusive", "new"];
|
|
||||||
pub const RANGE_STD: [&str; 3] = ["std", "ops", "Range"];
|
|
||||||
pub const RANGE_TO: [&str; 3] = ["core", "ops", "RangeTo"];
|
|
||||||
pub const RANGE_TO_INCLUSIVE: [&str; 3] = ["core", "ops", "RangeToInclusive"];
|
|
||||||
pub const RANGE_TO_INCLUSIVE_STD: [&str; 3] = ["std", "ops", "RangeToInclusive"];
|
|
||||||
pub const RANGE_TO_STD: [&str; 3] = ["std", "ops", "RangeTo"];
|
|
||||||
pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
|
pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
|
||||||
pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
|
pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
|
||||||
pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"];
|
pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"];
|
||||||
|
@ -130,7 +118,6 @@ pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
|
||||||
pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
|
pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
|
||||||
pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
|
pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
|
||||||
pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
|
pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
|
||||||
pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"];
|
|
||||||
pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"];
|
pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"];
|
||||||
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
|
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
|
||||||
pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
|
pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl<'a> Sugg<'a> {
|
||||||
pub fn hir_opt(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Self> {
|
pub fn hir_opt(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Self> {
|
||||||
snippet_opt(cx, expr.span).map(|snippet| {
|
snippet_opt(cx, expr.span).map(|snippet| {
|
||||||
let snippet = Cow::Owned(snippet);
|
let snippet = Cow::Owned(snippet);
|
||||||
Self::hir_from_snippet(cx, expr, snippet)
|
Self::hir_from_snippet(expr, snippet)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,13 +80,13 @@ impl<'a> Sugg<'a> {
|
||||||
pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
|
pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
|
||||||
let snippet = snippet_with_macro_callsite(cx, expr.span, default);
|
let snippet = snippet_with_macro_callsite(cx, expr.span, default);
|
||||||
|
|
||||||
Self::hir_from_snippet(cx, expr, snippet)
|
Self::hir_from_snippet(expr, snippet)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
|
/// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
|
||||||
/// function variants of `Sugg`, since these use different snippet functions.
|
/// function variants of `Sugg`, since these use different snippet functions.
|
||||||
fn hir_from_snippet(cx: &LateContext<'_>, expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
|
fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
|
||||||
if let Some(range) = higher::range(cx, expr) {
|
if let Some(range) = higher::range(expr) {
|
||||||
let op = match range.limits {
|
let op = match range.limits {
|
||||||
ast::RangeLimits::HalfOpen => AssocOp::DotDot,
|
ast::RangeLimits::HalfOpen => AssocOp::DotDot,
|
||||||
ast::RangeLimits::Closed => AssocOp::DotDotEq,
|
ast::RangeLimits::Closed => AssocOp::DotDotEq,
|
||||||
|
|
|
@ -3,10 +3,10 @@ if_chain! {
|
||||||
if let ExprKind::Match(ref expr1, ref arms, MatchSource::ForLoopDesugar) = expr.kind;
|
if let ExprKind::Match(ref expr1, ref arms, MatchSource::ForLoopDesugar) = expr.kind;
|
||||||
if let ExprKind::Call(ref func, ref args) = expr1.kind;
|
if let ExprKind::Call(ref func, ref args) = expr1.kind;
|
||||||
if let ExprKind::Path(ref path) = func.kind;
|
if let ExprKind::Path(ref path) = func.kind;
|
||||||
if match_qpath(path, &["{{root}}", "std", "iter", "IntoIterator", "into_iter"]);
|
if matches!(path, QPath::LangItem(LangItem::IntoIterIntoIter, _));
|
||||||
if args.len() == 1;
|
if args.len() == 1;
|
||||||
if let ExprKind::Struct(ref path1, ref fields, None) = args[0].kind;
|
if let ExprKind::Struct(ref path1, ref fields, None) = args[0].kind;
|
||||||
if match_qpath(path1, &["{{root}}", "std", "ops", "Range"]);
|
if matches!(path1, QPath::LangItem(LangItem::Range, _));
|
||||||
if fields.len() == 2;
|
if fields.len() == 2;
|
||||||
// unimplemented: field checks
|
// unimplemented: field checks
|
||||||
if arms.len() == 1;
|
if arms.len() == 1;
|
||||||
|
@ -20,7 +20,7 @@ if_chain! {
|
||||||
if let ExprKind::Match(ref expr2, ref arms1, MatchSource::ForLoopDesugar) = e.kind;
|
if let ExprKind::Match(ref expr2, ref arms1, MatchSource::ForLoopDesugar) = e.kind;
|
||||||
if let ExprKind::Call(ref func1, ref args1) = expr2.kind;
|
if let ExprKind::Call(ref func1, ref args1) = expr2.kind;
|
||||||
if let ExprKind::Path(ref path2) = func1.kind;
|
if let ExprKind::Path(ref path2) = func1.kind;
|
||||||
if match_qpath(path2, &["{{root}}", "std", "iter", "Iterator", "next"]);
|
if matches!(path2, QPath::LangItem(LangItem::IteratorNext, _));
|
||||||
if args1.len() == 1;
|
if args1.len() == 1;
|
||||||
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, ref inner) = args1[0].kind;
|
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, ref inner) = args1[0].kind;
|
||||||
if let ExprKind::Path(ref path3) = inner.kind;
|
if let ExprKind::Path(ref path3) = inner.kind;
|
||||||
|
@ -31,13 +31,15 @@ if_chain! {
|
||||||
if match_qpath(path4, &["__next"]);
|
if match_qpath(path4, &["__next"]);
|
||||||
if let ExprKind::Path(ref path5) = value.kind;
|
if let ExprKind::Path(ref path5) = value.kind;
|
||||||
if match_qpath(path5, &["val"]);
|
if match_qpath(path5, &["val"]);
|
||||||
if let PatKind::TupleStruct(ref path6, ref fields1, None) = arms1[0].pat.kind;
|
if let PatKind::Struct(ref path6, ref fields1, false) = arms1[0].pat.kind;
|
||||||
if match_qpath(path6, &["{{root}}", "std", "option", "Option", "Some"]);
|
if matches!(path6, QPath::LangItem(LangItem::OptionSome, _));
|
||||||
if fields1.len() == 1;
|
if fields1.len() == 1;
|
||||||
// unimplemented: field checks
|
// unimplemented: field checks
|
||||||
if let ExprKind::Break(ref destination, None) = arms1[1].body.kind;
|
if let ExprKind::Break(ref destination, None) = arms1[1].body.kind;
|
||||||
if let PatKind::Path(ref path7) = arms1[1].pat.kind;
|
if let PatKind::Struct(ref path7, ref fields2, false) = arms1[1].pat.kind;
|
||||||
if match_qpath(path7, &["{{root}}", "std", "option", "Option", "None"]);
|
if matches!(path7, QPath::LangItem(LangItem::OptionNone, _));
|
||||||
|
if fields2.len() == 0;
|
||||||
|
// unimplemented: field checks
|
||||||
if let StmtKind::Local(ref local1) = body.stmts[2].kind;
|
if let StmtKind::Local(ref local1) = body.stmts[2].kind;
|
||||||
if let Some(ref init) = local1.init;
|
if let Some(ref init) = local1.init;
|
||||||
if let ExprKind::Path(ref path8) = init.kind;
|
if let ExprKind::Path(ref path8) = init.kind;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue