From 764dc3dc2f8a2a421fa9d9c6144ad75310a26b99 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 10:27:35 +0100 Subject: [PATCH 1/9] lang_items: add support for lang items on variants This commit adds support for lang items (`#[lang = "..."]` attributes) on enum variants. Signed-off-by: David Wood --- src/librustc_hir/target.rs | 2 ++ src/librustc_passes/lang_items.rs | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc_hir/target.rs b/src/librustc_hir/target.rs index 3a4485a1b17fd..1efc8bc3124b6 100644 --- a/src/librustc_hir/target.rs +++ b/src/librustc_hir/target.rs @@ -29,6 +29,7 @@ pub enum Target { TyAlias, OpaqueTy, Enum, + Variant, Struct, Union, Trait, @@ -62,6 +63,7 @@ impl Display for Target { Target::TyAlias => "type alias", Target::OpaqueTy => "opaque type", Target::Enum => "enum", + Target::Variant => "enum variant", Target::Struct => "struct", Target::Union => "union", Target::Trait => "trait", diff --git a/src/librustc_passes/lang_items.rs b/src/librustc_passes/lang_items.rs index 07415870549f1..9ec47d2d9ab5c 100644 --- a/src/librustc_passes/lang_items.rs +++ b/src/librustc_passes/lang_items.rs @@ -30,7 +30,13 @@ struct LanguageItemCollector<'tcx> { impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> { 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<'_>) { From 734441c1ae5f0766842d37db68f606a1bca49836 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 10:47:07 +0100 Subject: [PATCH 2/9] tests: add test for #61019's current behaviour This commit adds a test for #61019 where a extern crate is imported as `std` which results in name resolution to fail due to the uses of `std` types introduced from lowering. Signed-off-by: David Wood --- src/test/ui/hygiene/hir-res-hygiene.rs | 41 ++++++++++++++++++ src/test/ui/hygiene/hir-res-hygiene.stderr | 49 ++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/test/ui/hygiene/hir-res-hygiene.rs create mode 100644 src/test/ui/hygiene/hir-res-hygiene.stderr diff --git a/src/test/ui/hygiene/hir-res-hygiene.rs b/src/test/ui/hygiene/hir-res-hygiene.rs new file mode 100644 index 0000000000000..e5af1000dd53e --- /dev/null +++ b/src/test/ui/hygiene/hir-res-hygiene.rs @@ -0,0 +1,41 @@ +//~ ERROR failed to resolve: could not find `future` in `std` [E0433] +//~^ ERROR failed to resolve: could not find `pin` in `std` [E0433] +//~^^ ERROR failed to resolve: could not find `future` in `std` [E0433] +//~^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] +//~^^^^ ERROR failed to resolve: could not find `task` in `std` [E0433] +//~^^^^^ ERROR failed to resolve: could not find `task` in `std` [E0433] +//~^^^^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] +//~^^^^^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] +//~^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] +//~^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] +//~^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] +//~^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] +//~^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] +//~^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] +//~^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] +//~^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] +//~^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `result` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `convert` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] +//~^^^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `result` in `std` [E0433] + +// 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(()) +} diff --git a/src/test/ui/hygiene/hir-res-hygiene.stderr b/src/test/ui/hygiene/hir-res-hygiene.stderr new file mode 100644 index 0000000000000..73a1bd5c62632 --- /dev/null +++ b/src/test/ui/hygiene/hir-res-hygiene.stderr @@ -0,0 +1,49 @@ +error[E0433]: failed to resolve: could not find `future` in `std` + +error[E0433]: failed to resolve: could not find `pin` in `std` + +error[E0433]: failed to resolve: could not find `future` in `std` + +error[E0433]: failed to resolve: could not find `future` in `std` + +error[E0433]: failed to resolve: could not find `task` in `std` + +error[E0433]: failed to resolve: could not find `task` in `std` + +error[E0433]: failed to resolve: could not find `future` in `std` + +error[E0433]: failed to resolve: could not find `future` in `std` + +error[E0433]: failed to resolve: could not find `ops` in `std` + +error[E0433]: failed to resolve: could not find `option` in `std` + +error[E0433]: failed to resolve: could not find `option` in `std` + +error[E0433]: failed to resolve: could not find `iter` in `std` + +error[E0433]: failed to resolve: could not find `iter` in `std` + +error[E0433]: failed to resolve: could not find `ops` in `std` + +error[E0433]: failed to resolve: could not find `option` in `std` + +error[E0433]: failed to resolve: could not find `option` in `std` + +error[E0433]: failed to resolve: could not find `iter` in `std` + +error[E0433]: failed to resolve: could not find `iter` in `std` + +error[E0433]: failed to resolve: could not find `ops` in `std` + +error[E0433]: failed to resolve: could not find `result` in `std` + +error[E0433]: failed to resolve: could not find `convert` in `std` + +error[E0433]: failed to resolve: could not find `ops` in `std` + +error[E0433]: failed to resolve: could not find `result` in `std` + +error: aborting due to 23 previous errors + +For more information about this error, try `rustc --explain E0433`. From 7dee5f824dad65d9edffb4de22aad248bd83faf9 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:04:25 +0100 Subject: [PATCH 3/9] hir: introduce lang items for AST lowering This commit adds new lang items which will be used in AST lowering once `QPath::LangItem` is introduced. Co-authored-by: Matthew Jasper Signed-off-by: David Wood --- library/core/src/convert/mod.rs | 1 + library/core/src/future/future.rs | 1 + library/core/src/future/mod.rs | 2 ++ library/core/src/iter/traits/collect.rs | 1 + library/core/src/iter/traits/iterator.rs | 1 + library/core/src/ops/range.rs | 7 +++++ library/core/src/ops/try.rs | 3 ++ library/core/src/option.rs | 2 ++ library/core/src/pin.rs | 1 + library/core/src/result.rs | 2 ++ library/core/src/task/poll.rs | 2 ++ src/librustc_hir/lang_items.rs | 36 +++++++++++++++++++++++- src/librustc_span/symbol.rs | 2 ++ 13 files changed, 60 insertions(+), 1 deletion(-) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 03b798d57db9b..fcd07befae504 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -385,6 +385,7 @@ pub trait Into: Sized { ))] pub trait From: Sized { /// Performs the conversion. + #[cfg_attr(not(bootstrap), lang = "from")] #[stable(feature = "rust1", since = "1.0.0")] fn from(_: T) -> Self; } diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index 733ebdc0e97f2..8169c146137c2 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -96,6 +96,7 @@ pub trait Future { /// [`Context`]: ../task/struct.Context.html /// [`Waker`]: ../task/struct.Waker.html /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake + #[cfg_attr(not(bootstrap), lang = "poll")] #[stable(feature = "futures_api", since = "1.36.0")] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 6d1ad9db74435..d44ef857c133a 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -53,6 +53,7 @@ unsafe impl Sync for ResumeTy {} /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). // This is `const` to avoid extra errors after we recover from `const async fn` +#[cfg_attr(not(bootstrap), lang = "from_generator")] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[inline] @@ -85,6 +86,7 @@ where GenFuture(gen) } +#[cfg_attr(not(bootstrap), lang = "get_context")] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[inline] diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 9d20022b6ed6d..84c7787a18fd1 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -235,6 +235,7 @@ pub trait IntoIterator { /// assert_eq!(Some(3), iter.next()); /// assert_eq!(None, iter.next()); /// ``` + #[cfg_attr(not(bootstrap), lang = "into_iter")] #[stable(feature = "rust1", since = "1.0.0")] fn into_iter(self) -> Self::IntoIter; } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f89b616c4e23b..81d8f27ec19b0 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -129,6 +129,7 @@ pub trait Iterator { /// assert_eq!(None, iter.next()); /// assert_eq!(None, iter.next()); /// ``` + #[cfg_attr(not(bootstrap), lang = "next")] #[stable(feature = "rust1", since = "1.0.0")] fn next(&mut self) -> Option; diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 179038d1977c8..e9ab82b539849 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -38,6 +38,7 @@ use crate::hash::Hash; /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[cfg_attr(not(bootstrap), lang = "RangeFull")] #[doc(alias = "..")] #[derive(Copy, Clone, Default, PartialEq, Eq, Hash)] #[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,3 ]); /// ``` +#[cfg_attr(not(bootstrap), lang = "Range")] #[doc(alias = "..")] #[derive(Clone, Default, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] @@ -178,6 +180,7 @@ impl> Range { /// ``` /// /// [`Iterator`]: ../iter/trait.IntoIterator.html +#[cfg_attr(not(bootstrap), lang = "RangeFrom")] #[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] @@ -260,6 +263,7 @@ impl> RangeFrom { /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[cfg_attr(not(bootstrap), lang = "RangeTo")] #[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] @@ -328,6 +332,7 @@ impl> RangeTo { /// assert_eq!(arr[1.. 3], [ 1,2 ]); /// assert_eq!(arr[1..=3], [ 1,2,3 ]); // RangeInclusive /// ``` +#[cfg_attr(not(bootstrap), lang = "RangeInclusive")] #[doc(alias = "..=")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] @@ -359,6 +364,7 @@ impl RangeInclusive { /// /// 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")] #[inline] #[rustc_promotable] @@ -555,6 +561,7 @@ impl> RangeInclusive { /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[cfg_attr(not(bootstrap), lang = "RangeToInclusive")] #[doc(alias = "..=")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "inclusive_range", since = "1.26.0")] diff --git a/library/core/src/ops/try.rs b/library/core/src/ops/try.rs index 9bc35ae1f5c28..e6b05cc641e35 100644 --- a/library/core/src/ops/try.rs +++ b/library/core/src/ops/try.rs @@ -43,16 +43,19 @@ pub trait Try { /// in the return type of the enclosing scope (which must itself implement /// `Try`). Specifically, the value `X::from_error(From::from(e))` /// 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")] fn into_result(self) -> Result; /// Wrap an error value to construct the composite result. For example, /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. + #[cfg_attr(not(bootstrap), lang = "from_error")] #[unstable(feature = "try_trait", issue = "42327")] fn from_error(v: Self::Error) -> Self; /// Wrap an OK value to construct the composite result. For example, /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. + #[cfg_attr(not(bootstrap), lang = "from_ok")] #[unstable(feature = "try_trait", issue = "42327")] fn from_ok(v: Self::Ok) -> Self; } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 6d078fb0a54d6..b6aa2c6697123 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -144,9 +144,11 @@ use crate::{ #[stable(feature = "rust1", since = "1.0.0")] pub enum Option { /// No value + #[cfg_attr(not(bootstrap), lang = "None")] #[stable(feature = "rust1", since = "1.0.0")] None, /// Some value `T` + #[cfg_attr(not(bootstrap), lang = "Some")] #[stable(feature = "rust1", since = "1.0.0")] Some(#[stable(feature = "rust1", since = "1.0.0")] T), } diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 9bcacd8ddcf77..c1a90a1fd8042 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -562,6 +562,7 @@ impl Pin

{ /// ``` /// /// [`mem::swap`]: ../../std/mem/fn.swap.html + #[cfg_attr(not(bootstrap), lang = "new_unchecked")] #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub unsafe fn new_unchecked(pointer: P) -> Pin

{ diff --git a/library/core/src/result.rs b/library/core/src/result.rs index e68dbf5215f6d..5eddcb2172abe 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -246,10 +246,12 @@ use crate::{convert, fmt}; #[stable(feature = "rust1", since = "1.0.0")] pub enum Result { /// Contains the success value + #[cfg_attr(not(bootstrap), lang = "Ok")] #[stable(feature = "rust1", since = "1.0.0")] Ok(#[stable(feature = "rust1", since = "1.0.0")] T), /// Contains the error value + #[cfg_attr(not(bootstrap), lang = "Err")] #[stable(feature = "rust1", since = "1.0.0")] Err(#[stable(feature = "rust1", since = "1.0.0")] E), } diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index b3a4bd20b8f04..fea396d20ff4b 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -10,6 +10,7 @@ use crate::result::Result; #[stable(feature = "futures_api", since = "1.36.0")] pub enum Poll { /// Represents that a value is immediately ready. + #[cfg_attr(not(bootstrap), lang = "Ready")] #[stable(feature = "futures_api", since = "1.36.0")] Ready(#[stable(feature = "futures_api", since = "1.36.0")] T), @@ -18,6 +19,7 @@ pub enum Poll { /// When a function returns `Pending`, the function *must* also /// ensure that the current task is scheduled to be awoken when /// progress can be made. + #[cfg_attr(not(bootstrap), lang = "Pending")] #[stable(feature = "futures_api", since = "1.36.0")] Pending, } diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index b09657bd9b4a4..d6c295f0ddb61 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -10,7 +10,7 @@ pub use self::LangItem::*; use crate::def_id::DefId; -use crate::Target; +use crate::{MethodKind, Target}; use rustc_ast::ast; use rustc_data_structures::fx::FxHashMap; @@ -307,4 +307,38 @@ language_item_table! { CountCodeRegionFnLangItem, sym::count_code_region, count_code_region_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; + + // 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; } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 7843c04f25596..bc7efd26f467b 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -706,6 +706,7 @@ symbols! { never_type, never_type_fallback, new, + new_unchecked, next, nll, no, @@ -828,6 +829,7 @@ symbols! { quad_precision_float, question_mark, quote, + range_inclusive_new, raw_dylib, raw_identifiers, raw_ref_op, From 762137e2121ac8998b5bb916453eb24ec6523450 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:34:24 +0100 Subject: [PATCH 4/9] hir: introduce `QPath::LangItem` This commit introduces `QPath::LangItem` to the HIR and uses it in AST lowering instead of constructing a `hir::Path` from a slice of symbols. This might be better for performance, but is also much cleaner as the previous approach is fragile. In addition, it resolves a bug (#61019) where an extern crate imported as "std" would result in the paths created during AST lowering being resolved incorrectly (or not at all). Co-authored-by: Matthew Jasper Signed-off-by: David Wood --- src/librustc_ast_lowering/expr.rs | 161 ++++++++------------- src/librustc_ast_lowering/lib.rs | 110 +++++--------- src/librustc_hir/hir.rs | 50 ++++++- src/librustc_hir/intravisit.rs | 5 + src/librustc_hir_pretty/lib.rs | 10 ++ src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/context.rs | 2 +- src/librustc_middle/ty/context.rs | 2 +- src/librustc_passes/liveness.rs | 6 +- src/librustc_privacy/lib.rs | 6 +- src/librustc_resolve/lib.rs | 31 ---- src/librustc_save_analysis/dump_visitor.rs | 4 + src/librustc_save_analysis/lib.rs | 3 + src/librustc_save_analysis/sig.rs | 1 + src/librustc_typeck/astconv.rs | 46 ++++++ src/librustc_typeck/check/expr.rs | 18 ++- src/librustc_typeck/check/mod.rs | 38 ++++- src/librustc_typeck/check/pat.rs | 8 +- src/librustc_typeck/collect.rs | 26 ++++ src/test/ui/hygiene/hir-res-hygiene.rs | 25 +--- src/test/ui/hygiene/hir-res-hygiene.stderr | 49 ------- 21 files changed, 289 insertions(+), 314 deletions(-) delete mode 100644 src/test/ui/hygiene/hir-res-hygiene.stderr diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index f9e54903a661a..65c9cd2e203d1 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -449,7 +449,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `::std::ops::Try::from_ok($tail_expr)` block.expr = Some(this.wrap_in_try_constructor( - sym::from_ok, + hir::LangItem::TryFromOk, try_span, tail_expr, ok_wrapped_span, @@ -461,14 +461,13 @@ impl<'hir> LoweringContext<'_, 'hir> { fn wrap_in_try_constructor( &mut self, - method: Symbol, + lang_item: hir::LangItem, method_span: Span, expr: &'hir hir::Expr<'hir>, overall_span: Span, ) -> &'hir hir::Expr<'hir> { - let path = &[sym::ops, sym::Try, method]; 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)) } @@ -558,12 +557,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // `future::from_generator`: let unstable_span = self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); - let gen_future = self.expr_std_path( - unstable_span, - &[sym::future, sym::from_generator], - None, - ThinVec::new(), - ); + let gen_future = + self.expr_lang_item_path(unstable_span, hir::LangItem::FromGenerator, ThinVec::new()); // `future::from_generator(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. self.expr_err(span) }; - let pin_ty_id = self.next_id(); - let new_unchecked_expr_kind = self.expr_call_std_assoc_fn( - pin_ty_id, + let new_unchecked = self.expr_call_lang_item_fn_mut( span, - &[sym::pin, sym::Pin], - "new_unchecked", + hir::LangItem::PinNewUnchecked, arena_vec![self; ref_mut_pinned], ); - let new_unchecked = self.expr(span, new_unchecked_expr_kind, ThinVec::new()); - let get_context = self.expr_call_std_path_mut( + let get_context = self.expr_call_lang_item_fn_mut( gen_future_span, - &[sym::future, sym::get_context], + hir::LangItem::GetContext, arena_vec![self; task_context], ); - let call = self.expr_call_std_path( + let call = self.expr_call_lang_item_fn( span, - &[sym::future, sym::Future, sym::poll], + hir::LangItem::FuturePoll, arena_vec![self; new_unchecked, get_context], ); 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_pat, x_pat_hid) = self.pat_ident(span, x_ident); let x_expr = self.expr_ident(span, x_ident, x_pat_hid); - let ready_pat = self.pat_std_enum( - span, - &[sym::task, sym::Poll, sym::Ready], - arena_vec![self; x_pat], - ); + let ready_field = self.single_pat_field(span, x_pat); + let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field); let break_x = self.with_loop_scope(loop_node_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); @@ -674,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `::std::task::Poll::Pending => {}` 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); self.arm(pending_pat, empty_block) }; @@ -842,16 +830,12 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Desugar `..=` into `std::ops::RangeInclusive::new(, )`. 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 e2 = self.lower_expr_mut(e2); - self.expr_call_std_assoc_fn( - id, - span, - &[sym::ops, sym::RangeInclusive], - "new", - arena_vec![self; e1, e2], - ) + let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span); + let fn_expr = + self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new())); + hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2]) } fn lower_expr_range( @@ -863,12 +847,12 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ExprKind<'hir> { use rustc_ast::ast::RangeLimits::*; - let path = match (e1, e2, lims) { - (None, None, HalfOpen) => sym::RangeFull, - (Some(..), None, HalfOpen) => sym::RangeFrom, - (None, Some(..), HalfOpen) => sym::RangeTo, - (Some(..), Some(..), HalfOpen) => sym::Range, - (None, Some(..), Closed) => sym::RangeToInclusive, + let lang_item = match (e1, e2, lims) { + (None, None, HalfOpen) => hir::LangItem::RangeFull, + (Some(..), None, HalfOpen) => hir::LangItem::RangeFrom, + (None, Some(..), HalfOpen) => hir::LangItem::RangeTo, + (Some(..), Some(..), HalfOpen) => hir::LangItem::Range, + (None, Some(..), Closed) => hir::LangItem::RangeToInclusive, (Some(..), Some(..), Closed) => unreachable!(), (_, None, Closed) => { 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(); - 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) - } + hir::ExprKind::Struct(self.arena.alloc(hir::QPath::LangItem(lang_item, span)), fields, None) } fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination { @@ -1412,9 +1387,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let match_expr = { let iter = self.expr_ident(desugared_span, iter, iter_pat_nid); 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_std_path(desugared_span, next_path, arena_vec![self; ref_mut_iter]); + let next_expr = self.expr_call_lang_item_fn( + desugared_span, + hir::LangItem::IteratorNext, + arena_vec![self; ref_mut_iter], + ); let arms = arena_vec![self; pat_arm, break_arm]; 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() { ... }` let into_iter_expr = { - let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter]; - self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head]) + self.expr_call_lang_item_fn( + into_iter_span, + hir::LangItem::IntoIterIntoIter, + arena_vec![self; head], + ) }; let match_expr = self.arena.alloc(self.expr_match( @@ -1521,8 +1501,11 @@ impl<'hir> LoweringContext<'_, 'hir> { // expand let sub_expr = self.lower_expr_mut(sub_expr); - let path = &[sym::ops, sym::Try, sym::into_result]; - self.expr_call_std_path(unstable_span, path, arena_vec![self; sub_expr]) + self.expr_call_lang_item_fn( + unstable_span, + hir::LangItem::TryIntoResult, + arena_vec![self; sub_expr], + ) }; // `#[allow(unreachable_code)]` @@ -1558,12 +1541,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let err_ident = Ident::with_dummy_span(sym::err); let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); 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); - 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 = - self.wrap_in_try_constructor(sym::from_error, unstable_span, from_expr, try_span); + let from_err_expr = self.wrap_in_try_constructor( + hir::LangItem::TryFromError, + unstable_span, + from_expr, + try_span, + ); let thin_attrs = ThinVec::from(attrs); let catch_scope = self.catch_scopes.last().copied(); 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)) } - // Note: associated functions must use `expr_call_std_path`. - fn expr_call_std_path_mut( + fn expr_call_lang_item_fn_mut( &mut self, span: Span, - path_components: &[Symbol], + lang_item: hir::LangItem, args: &'hir [hir::Expr<'hir>], ) -> hir::Expr<'hir> { - let path = - self.arena.alloc(self.expr_std_path(span, path_components, None, ThinVec::new())); + let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new())); self.expr_call_mut(span, path, args) } - fn expr_call_std_path( + fn expr_call_lang_item_fn( &mut self, span: Span, - path_components: &[Symbol], + lang_item: hir::LangItem, args: &'hir [hir::Expr<'hir>], ) -> &'hir hir::Expr<'hir> { - self.arena.alloc(self.expr_call_std_path_mut(span, path_components, args)) - } - - // Create an expression calling an associated function of an std type. - // - // 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) + self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args)) } - fn expr_std_path( + fn expr_lang_item_path( &mut self, span: Span, - components: &[Symbol], - params: Option<&'hir hir::GenericArgs<'hir>>, + lang_item: hir::LangItem, attrs: AttrVec, ) -> hir::Expr<'hir> { - let path = self.std_path(span, components, params, true); - self.expr(span, hir::ExprKind::Path(hir::QPath::Resolved(None, path)), attrs) + self.expr(span, hir::ExprKind::Path(hir::QPath::LangItem(lang_item, span)), attrs) } pub(super) fn expr_ident( diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 7cfde3fc6d2dc..a2962008a6bd4 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -85,8 +85,6 @@ const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; rustc_hir::arena_types!(rustc_arena::declare_arena, [], 'tcx); struct LoweringContext<'a, 'hir: 'a> { - crate_root: Option, - /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes. sess: &'a Session, @@ -189,16 +187,6 @@ pub trait ResolverAstLowering { /// This should only return `None` during testing. 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, - components: &[Symbol], - ns: Namespace, - ) -> (ast::Path, Res); - fn lint_buffer(&mut self) -> &mut LintBuffer; 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"); LoweringContext { - crate_root: sess.parse_sess.injected_crate_name.get().copied(), sess, resolver, nt_to_tokenstream, @@ -2064,23 +2051,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; // "" - let future_params = self.arena.alloc(hir::GenericArgs { + let future_args = self.arena.alloc(hir::GenericArgs { args: &[], bindings: arena_vec![self; self.output_ty_binding(span, output_ty)], parenthesized: false, }); - // ::std::future::Future - let future_path = - self.std_path(span, &[sym::future, sym::Future], Some(future_params), false); - - hir::GenericBound::Trait( - hir::PolyTraitRef { - trait_ref: hir::TraitRef { path: future_path, hir_ref_id: self.next_id() }, - bound_generic_params: &[], - span, - }, - hir::TraitBoundModifier::None, + hir::GenericBound::LangItemTrait( + // ::std::future::Future + hir::LangItem::FutureTraitLangItem, + span, + self.next_id(), + future_args, ) } @@ -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> { - 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> { - 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> { - 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> { - 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, span: Span, - components: &[Symbol], - subpats: &'hir [&'hir hir::Pat<'hir>], - ) -> &'hir hir::Pat<'hir> { - let path = self.std_path(span, components, None, true); - let qpath = hir::QPath::Resolved(None, path); - let pt = if subpats.is_empty() { - hir::PatKind::Path(qpath) - } else { - hir::PatKind::TupleStruct(qpath, subpats, None) + pat: &'hir hir::Pat<'hir>, + ) -> &'hir [hir::FieldPat<'hir>] { + let field = hir::FieldPat { + hir_id: self.next_id(), + ident: Ident::new(sym::integer(0), span), + is_shorthand: false, + pat, + span, }; - 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) { @@ -2541,42 +2535,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { 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( &mut self, mut hir_id: hir::HirId, diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 928235adac30c..e1ec60bcc0a2c 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -1,7 +1,7 @@ use crate::def::{DefKind, Namespace, Res}; use crate::def_id::DefId; crate use crate::hir_id::HirId; -use crate::itemlikevisit; +use crate::{itemlikevisit, LangItem}; use rustc_ast::ast::{self, CrateSugar, LlvmAsmDialect}; use rustc_ast::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy}; @@ -363,6 +363,8 @@ pub enum TraitBoundModifier { #[derive(Debug, HashStable_Generic)] pub enum GenericBound<'hir> { Trait(PolyTraitRef<'hir>, TraitBoundModifier), + // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem` + LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>), Outlives(Lifetime), } @@ -377,6 +379,7 @@ impl GenericBound<'_> { pub fn span(&self) -> Span { match self { &GenericBound::Trait(ref t, ..) => t.span, + &GenericBound::LangItemTrait(_, span, ..) => span, &GenericBound::Outlives(ref l) => l.span, } } @@ -1419,10 +1422,10 @@ impl Expr<'_> { self.is_place_expr(|_| true) } - // 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 - // 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 place expression. pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool { match self.kind { 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) } + // Lang item paths cannot currently be local variables or statics. + ExprKind::Path(QPath::LangItem(..)) => false, + // Partially qualified paths in expressions can only legally // refer to associated items which are always rvalues. ExprKind::Path(QPath::TypeRelative(..)) @@ -1677,6 +1683,40 @@ pub enum QPath<'hir> { /// `::new`, and `T::X::Y::method` into `<<::X>::Y>::method`, /// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`. 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. diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs index 23d642731da4d..66ef017713447 100644 --- a/src/librustc_hir/intravisit.rs +++ b/src/librustc_hir/intravisit.rs @@ -724,6 +724,7 @@ pub fn walk_qpath<'v, V: Visitor<'v>>( visitor.visit_ty(qself); 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) => { 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), } } diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs index 2298a80ae4f1f..e124db9e355dd 100644 --- a/src/librustc_hir_pretty/lib.rs +++ b/src/librustc_hir_pretty/lib.rs @@ -1729,6 +1729,11 @@ impl<'a> State<'a> { 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); } + GenericBound::LangItemTrait(lang_item, span, ..) => { + self.s.word("#[lang = \""); + self.print_ident(Ident::new(lang_item.name(), *span)); + self.s.word("\"]"); + } GenericBound::Outlives(lt) => { self.print_lifetime(lt); } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3859d0f163ad5..97830e6c86f39 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1057,7 +1057,7 @@ impl TypeAliasBounds { _ => false, } } - hir::QPath::Resolved(..) => false, + hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false, } } diff --git a/src/librustc_lint/context.rs b/src/librustc_lint/context.rs index 31d30a264a59e..5b91b77e4f02d 100644 --- a/src/librustc_lint/context.rs +++ b/src/librustc_lint/context.rs @@ -703,7 +703,7 @@ impl<'tcx> LateContext<'tcx> { pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res { match *qpath { hir::QPath::Resolved(_, ref path) => path.res, - hir::QPath::TypeRelative(..) => self + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self .maybe_typeck_results() .and_then(|typeck_results| typeck_results.type_dependent_def(id)) .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 6887f72932267..3b10cb5388506 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -445,7 +445,7 @@ impl<'tcx> TypeckResults<'tcx> { pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res { match *qpath { hir::QPath::Resolved(_, ref path) => path.res, - hir::QPath::TypeRelative(..) => self + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self .type_dependent_def(id) .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), } diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 6477f8da008ad..62c8680a85798 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -526,7 +526,8 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { | hir::ExprKind::Yield(..) | hir::ExprKind::Type(..) | 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); } } @@ -1310,7 +1311,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::Lit(..) | 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 // at the label ident diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index a3f2668691fd8..deb4277cb3854 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1325,7 +1325,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { Res::Def(kind, def_id) => Some((kind, def_id)), _ => None, }, - hir::QPath::TypeRelative(..) => self + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self .maybe_typeck_results .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 sm = sess.source_map(); 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()), }; let kind = kind.descr(def_id); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 339a5ae6675e7..32b8ea410ad22 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1076,37 +1076,6 @@ impl ResolverAstLowering for Resolver<'_> { self.cstore().item_generics_num_lifetimes(def_id, sess) } - fn resolve_str_path( - &mut self, - span: Span, - crate_root: Option, - 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::>(); - - 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 { self.partial_res_map.get(&id).cloned() } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index f33d2f46aa269..c1c165a9901f8 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -705,6 +705,7 @@ impl<'tcx> DumpVisitor<'tcx> { let trait_ref = match *super_bound { hir::GenericBound::Trait(ref trait_ref, _) => trait_ref, hir::GenericBound::Outlives(..) => continue, + hir::GenericBound::LangItemTrait(..) => unimplemented!(), }; let trait_ref = &trait_ref.trait_ref; @@ -765,6 +766,7 @@ impl<'tcx> DumpVisitor<'tcx> { let span = match path { hir::QPath::Resolved(_, path) => path.span, hir::QPath::TypeRelative(_, segment) => segment.ident.span, + hir::QPath::LangItem(..) => unimplemented!(), }; if self.span.filter_generated(span) { return; @@ -783,6 +785,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.visit_ty(ty); std::slice::from_ref(*segment) } + hir::QPath::LangItem(..) => unimplemented!(), }; for seg in segments { if let Some(ref generic_args) = seg.args { @@ -1358,6 +1361,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { let sub_span = match path { hir::QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span, hir::QPath::TypeRelative(_, segment) => segment.ident.span, + hir::QPath::LangItem(..) => unimplemented!(), }; let span = self.span_from_span(sub_span); self.dumper.dump_ref(Ref { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index ca98ada4e5729..a7eb344ff09f7 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -555,6 +555,7 @@ impl<'tcx> SaveContext<'tcx> { let segment = match qpath { hir::QPath::Resolved(_, path) => path.segments.last().unwrap(), hir::QPath::TypeRelative(_, segment) => segment, + hir::QPath::LangItem(..) => unimplemented!(), }; match ty.kind { ty::Adt(def, _) => { @@ -639,6 +640,7 @@ impl<'tcx> SaveContext<'tcx> { hir::QPath::TypeRelative(..) => self .maybe_typeck_results .map_or(Res::Err, |typeck_results| typeck_results.qpath_res(qpath, hir_id)), + hir::QPath::LangItem(..) => unimplemented!(), }, Node::Binding(&hir::Pat { @@ -653,6 +655,7 @@ impl<'tcx> SaveContext<'tcx> { let segment = match path { hir::QPath::Resolved(_, path) => path.segments.last(), hir::QPath::TypeRelative(_, segment) => Some(*segment), + hir::QPath::LangItem(..) => unimplemented!(), }; segment.and_then(|seg| { self.get_path_segment_data(seg).or_else(|| self.get_path_segment_data_with_id(seg, id)) diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 33355c4c558fb..6a9ad3c38f496 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -286,6 +286,7 @@ impl<'hir> Sig for hir::Ty<'hir> { refs: vec![SigElement { id, start, end }], }) } + hir::TyKind::Path(hir::QPath::LangItem(..)) => unimplemented!(), hir::TyKind::TraitObject(bounds, ..) => { // FIXME recurse into bounds let bounds: Vec> = bounds diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5170a060c5fe0..5e52a5ef16fb5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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( &self, span: Span, @@ -1392,6 +1422,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_bounds.push((b, Constness::NotConst)) } 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), } } @@ -2960,6 +2994,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map(|(ty, _, _)| ty) .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) => { let length_def_id = tcx.hir().local_def_id(length.hir_id); let length = ty::Const::from_anon_const(tcx, length_def_id); diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index e88f13a1f3ab6..e2c90cce178fe 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -236,6 +236,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::AddrOf(kind, mutbl, ref oprnd) => { 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::InlineAsm(asm) => self.check_expr_asm(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> { let tcx = self.tcx; 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(); }; - 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. 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() { @@ -1099,7 +1105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adt_ty, expected, expr.hir_id, - path_span, + qpath.span(), variant, fields, base_expr.is_none(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a625b5ea40567..c46d2388f3d93 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -122,10 +122,9 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts}; use rustc_middle::ty::util::{Discr, IntTypeExt, Representability}; -use rustc_middle::ty::{ - self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef, - ToPredicate, Ty, TyCtxt, UserType, WithConstness, -}; +use rustc_middle::ty::WithConstness; +use rustc_middle::ty::{self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind}; +use rustc_middle::ty::{RegionKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType}; use rustc_session::config::{self, EntryFnType}; use rustc_session::lint; use rustc_session::parse::feature_err; @@ -4430,10 +4429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath: &QPath<'_>, hir_id: hir::HirId, ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { - let path_span = match *qpath { - QPath::Resolved(_, ref path) => path.span, - QPath::TypeRelative(ref qself, _) => qself.span, - }; + let path_span = qpath.qself_span(); let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); let variant = match def { 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) } + 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 /// resolution. The newly resolved definition is written into `type_dependent_defs`. 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::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) { diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 1c78bef98527a..35c7b7a703cc0 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -947,13 +947,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // | // L | let A(()) = A(()); // | ^ ^ - [] => { - 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) - } + [] => (qpath.span().shrink_to_hi(), pat_span), // 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. // This looks like: diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index da1f3ea62f239..15743b0643662 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1959,6 +1959,20 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat 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) => { let region = AstConv::ast_region_to_region(&icx, lifetime, None); predicates.push(( @@ -2108,6 +2122,18 @@ fn predicates_from_bound<'tcx>( let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds); 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) => { let region = astconv.ast_region_to_region(lifetime, None); let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region)) diff --git a/src/test/ui/hygiene/hir-res-hygiene.rs b/src/test/ui/hygiene/hir-res-hygiene.rs index e5af1000dd53e..c26cf5fdb5b05 100644 --- a/src/test/ui/hygiene/hir-res-hygiene.rs +++ b/src/test/ui/hygiene/hir-res-hygiene.rs @@ -1,27 +1,4 @@ -//~ ERROR failed to resolve: could not find `future` in `std` [E0433] -//~^ ERROR failed to resolve: could not find `pin` in `std` [E0433] -//~^^ ERROR failed to resolve: could not find `future` in `std` [E0433] -//~^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] -//~^^^^ ERROR failed to resolve: could not find `task` in `std` [E0433] -//~^^^^^ ERROR failed to resolve: could not find `task` in `std` [E0433] -//~^^^^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] -//~^^^^^^^ ERROR failed to resolve: could not find `future` in `std` [E0433] -//~^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] -//~^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] -//~^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] -//~^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] -//~^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] -//~^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] -//~^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] -//~^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433] -//~^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `result` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `convert` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433] -//~^^^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `result` in `std` [E0433] - +// check-pass // edition:2018 // aux-build:not-libstd.rs diff --git a/src/test/ui/hygiene/hir-res-hygiene.stderr b/src/test/ui/hygiene/hir-res-hygiene.stderr deleted file mode 100644 index 73a1bd5c62632..0000000000000 --- a/src/test/ui/hygiene/hir-res-hygiene.stderr +++ /dev/null @@ -1,49 +0,0 @@ -error[E0433]: failed to resolve: could not find `future` in `std` - -error[E0433]: failed to resolve: could not find `pin` in `std` - -error[E0433]: failed to resolve: could not find `future` in `std` - -error[E0433]: failed to resolve: could not find `future` in `std` - -error[E0433]: failed to resolve: could not find `task` in `std` - -error[E0433]: failed to resolve: could not find `task` in `std` - -error[E0433]: failed to resolve: could not find `future` in `std` - -error[E0433]: failed to resolve: could not find `future` in `std` - -error[E0433]: failed to resolve: could not find `ops` in `std` - -error[E0433]: failed to resolve: could not find `option` in `std` - -error[E0433]: failed to resolve: could not find `option` in `std` - -error[E0433]: failed to resolve: could not find `iter` in `std` - -error[E0433]: failed to resolve: could not find `iter` in `std` - -error[E0433]: failed to resolve: could not find `ops` in `std` - -error[E0433]: failed to resolve: could not find `option` in `std` - -error[E0433]: failed to resolve: could not find `option` in `std` - -error[E0433]: failed to resolve: could not find `iter` in `std` - -error[E0433]: failed to resolve: could not find `iter` in `std` - -error[E0433]: failed to resolve: could not find `ops` in `std` - -error[E0433]: failed to resolve: could not find `result` in `std` - -error[E0433]: failed to resolve: could not find `convert` in `std` - -error[E0433]: failed to resolve: could not find `ops` in `std` - -error[E0433]: failed to resolve: could not find `result` in `std` - -error: aborting due to 23 previous errors - -For more information about this error, try `rustc --explain E0433`. From 1e2f350d921e73d7165fe9d7a5f0f6cfe613e3df Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:36:09 +0100 Subject: [PATCH 5/9] save_analysis: support `QPath::LangItem` This commit implements support for `QPath::LangItem` and `GenericBound::LangItemTrait` in save analysis. Signed-off-by: David Wood --- src/librustc_save_analysis/dump_visitor.rs | 30 +++++++--------- src/librustc_save_analysis/lib.rs | 42 +++++++++------------- src/librustc_save_analysis/sig.rs | 4 ++- 3 files changed, 32 insertions(+), 44 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index c1c165a9901f8..6e56e3b9ebb70 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -702,15 +702,18 @@ impl<'tcx> DumpVisitor<'tcx> { // super-traits for super_bound in trait_refs.iter() { - let trait_ref = match *super_bound { - hir::GenericBound::Trait(ref trait_ref, _) => trait_ref, + let (def_id, sub_span) = match *super_bound { + 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::LangItemTrait(..) => unimplemented!(), }; - let trait_ref = &trait_ref.trait_ref; - 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 let Some(id) = def_id { if !self.span.filter_generated(sub_span) { let span = self.span_from_span(sub_span); self.dumper.dump_ref(Ref { @@ -763,12 +766,7 @@ impl<'tcx> DumpVisitor<'tcx> { } fn process_path(&mut self, id: hir::HirId, path: &hir::QPath<'tcx>) { - let span = match path { - hir::QPath::Resolved(_, path) => path.span, - hir::QPath::TypeRelative(_, segment) => segment.ident.span, - hir::QPath::LangItem(..) => unimplemented!(), - }; - if self.span.filter_generated(span) { + if self.span.filter_generated(path.span()) { return; } self.dump_path_ref(id, path); @@ -785,7 +783,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.visit_ty(ty); std::slice::from_ref(*segment) } - hir::QPath::LangItem(..) => unimplemented!(), + hir::QPath::LangItem(..) => return, }; for seg in segments { if let Some(ref generic_args) = seg.args { @@ -1358,11 +1356,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } if let Some(id) = self.lookup_def_id(t.hir_id) { - let sub_span = match path { - hir::QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span, - hir::QPath::TypeRelative(_, segment) => segment.ident.span, - hir::QPath::LangItem(..) => unimplemented!(), - }; + let sub_span = path.last_segment_span(); let span = self.span_from_span(sub_span); self.dumper.dump_ref(Ref { kind: RefKind::Type, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index a7eb344ff09f7..fc8a5384739de 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -551,29 +551,22 @@ impl<'tcx> SaveContext<'tcx> { } } } - hir::ExprKind::Struct(qpath, ..) => { - let segment = match qpath { - hir::QPath::Resolved(_, path) => path.segments.last().unwrap(), - hir::QPath::TypeRelative(_, segment) => segment, - hir::QPath::LangItem(..) => unimplemented!(), - }; - match ty.kind { - ty::Adt(def, _) => { - let sub_span = segment.ident.span; - filter!(self.span_utils, sub_span); - 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 - } + hir::ExprKind::Struct(qpath, ..) => match ty.kind { + ty::Adt(def, _) => { + let sub_span = qpath.last_segment_span(); + filter!(self.span_utils, sub_span); + 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 + } + }, hir::ExprKind::MethodCall(ref seg, ..) => { let method_id = match self.typeck_results().type_dependent_def_id(expr.hir_id) { Some(id) => id, @@ -637,10 +630,9 @@ impl<'tcx> SaveContext<'tcx> { }) | Node::Ty(&hir::Ty { kind: hir::TyKind::Path(ref qpath), .. }) => match qpath { hir::QPath::Resolved(_, path) => path.res, - hir::QPath::TypeRelative(..) => self + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self .maybe_typeck_results .map_or(Res::Err, |typeck_results| typeck_results.qpath_res(qpath, hir_id)), - hir::QPath::LangItem(..) => unimplemented!(), }, Node::Binding(&hir::Pat { @@ -655,7 +647,7 @@ impl<'tcx> SaveContext<'tcx> { let segment = match path { hir::QPath::Resolved(_, path) => path.segments.last(), hir::QPath::TypeRelative(_, segment) => Some(*segment), - hir::QPath::LangItem(..) => unimplemented!(), + hir::QPath::LangItem(..) => None, }; segment.and_then(|seg| { self.get_path_segment_data(seg).or_else(|| self.get_path_segment_data_with_id(seg, id)) diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 6a9ad3c38f496..f6869cbbfd2aa 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -286,7 +286,9 @@ impl<'hir> Sig for hir::Ty<'hir> { refs: vec![SigElement { id, start, end }], }) } - hir::TyKind::Path(hir::QPath::LangItem(..)) => unimplemented!(), + hir::TyKind::Path(hir::QPath::LangItem(lang_item, _)) => { + Ok(text_sig(format!("#[lang = \"{}\"]", lang_item.name()))) + } hir::TyKind::TraitObject(bounds, ..) => { // FIXME recurse into bounds let bounds: Vec> = bounds From 664ecf1085b1bab9d7444eb54dccfeeabd99446e Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:18:11 +0100 Subject: [PATCH 6/9] hir: simplify `is_range_literal` This commit simplifies `is_range_literal` by checking for `QPath::LangItem` containing range-related lang items, rather than using a heuristic. Co-authored-by: Matthew Jasper Signed-off-by: David Wood --- src/librustc_hir/hir.rs | 60 ++++++++--------------------- src/librustc_lint/types.rs | 4 +- src/librustc_typeck/check/demand.rs | 2 +- src/test/ui/range/range-1.stderr | 6 ++- 4 files changed, 23 insertions(+), 49 deletions(-) diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index e1ec60bcc0a2c..bfcb506f1326f 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -13,7 +13,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_macros::HashStable_Generic; 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::{MultiSpan, Span, DUMMY_SP}; use rustc_target::asm::InlineAsmRegOrRegClass; @@ -1495,58 +1495,28 @@ impl Expr<'_> { /// Checks if the specified expression is a built-in range literal. /// (See: `LoweringContext::lower_expr()`). -/// -/// 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) - }; - +pub fn is_range_literal(expr: &Expr<'_>) -> bool { match expr.kind { // All built-in range literals but `..=` and `..` desugar to `Struct`s. - ExprKind::Struct(ref qpath, _, _) => { - if let QPath::Resolved(None, ref path) = **qpath { - return is_range_path(&path) && is_lit(sm, &expr.span); - } - } - - // `..` desugars to its struct path. - ExprKind::Path(QPath::Resolved(None, ref path)) => { - return is_range_path(&path) && is_lit(sm, &expr.span); - } + ExprKind::Struct(ref qpath, _, _) => matches!( + **qpath, + QPath::LangItem( + LangItem::Range + | LangItem::RangeTo + | LangItem::RangeFrom + | LangItem::RangeFull + | LangItem::RangeToInclusive, + _, + ) + ), // `..=` desugars into `::std::ops::RangeInclusive::new(...)`. ExprKind::Call(ref func, _) => { - if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind { - 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; - } - } + matches!(func.kind, ExprKind::Path(QPath::LangItem(LangItem::RangeInclusiveNew, _))) } - _ => {} + _ => false, } - - false } #[derive(Debug, HashStable_Generic)] diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 5891abcfd9cd1..a1c9b05a684dd 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -258,7 +258,7 @@ fn lint_int_literal<'tcx>( 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 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()) { // The overflowing literal lint was overridden. @@ -317,7 +317,7 @@ fn lint_uint_literal<'tcx>( 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(); if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) { // The overflowing literal lint was overridden. diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 4ea76a4a9e2ab..ad97dbe63d8b3 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -485,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parenthesize if needed (Issue #46756) hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, // 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, }; let sugg_expr = if needs_parens { format!("({})", src) } else { src }; diff --git a/src/test/ui/range/range-1.stderr b/src/test/ui/range/range-1.stderr index e179feba7a799..11cb72fa2b6f8 100644 --- a/src/test/ui/range/range-1.stderr +++ b/src/test/ui/range/range-1.stderr @@ -17,9 +17,13 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi | LL | let range = *arr..; | ^^^^^^ doesn't have a size known at compile-time + | + ::: $SRC_DIR/core/src/ops/range.rs:LL:COL + | +LL | pub struct RangeFrom { + | --- required by this bound in `std::ops::RangeFrom` | = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` - = note: required by `std::ops::RangeFrom` error: aborting due to 3 previous errors From 8367af469b9005c8f5c1777a48548a80e4658076 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:19:28 +0100 Subject: [PATCH 7/9] resolve: support `GenericBound::LangItemTrait` This commit modifies name resolution to ensure that new scopes are introduced from lang-item generic bounds. Co-authored-by: Matthew Jasper Signed-off-by: David Wood --- src/librustc_resolve/late/lifetimes.rs | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index e2f0d388f7e53..31360d474736a 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -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( &mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>, @@ -2296,6 +2314,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { 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) { if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { match lifetime { From dde93c9ba61e441bcafab84a1e42cddb32aa0178 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:22:16 +0100 Subject: [PATCH 8/9] rustdoc: clean `QPath::LangItem` This commit adds support for cleaning `QPath::LangItem` and `hir::GenericBound::LangItemTrait` in rustdoc. `QPath::LangItem` does not require lowering, and `hir::GenericBound::LangItemTrait` is lowered to a `GenericBound::TraitBound`. Signed-off-by: David Wood --- src/librustdoc/clean/mod.rs | 20 ++++++++++++++++++++ src/librustdoc/clean/utils.rs | 1 + 2 files changed, 21 insertions(+) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3ad357e583cf1..bf385fd79b0f2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -17,6 +17,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; +use rustc_middle::bug; use rustc_middle::middle::resolve_lifetime as rl; use rustc_middle::middle::stability; use rustc_middle::ty::fold::TypeFolder; @@ -291,6 +292,22 @@ impl Clean for hir::GenericBound<'_> { fn clean(&self, cx: &DocContext<'_>) -> GenericBound { match *self { 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) => { GenericBound::TraitBound(t.clean(cx), modifier) } @@ -1504,6 +1521,9 @@ impl Clean for hir::Ty<'_> { 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) => { match bounds[0].clean(cx).trait_ { ResolvedPath { path, param_names: None, did, is_generic } => { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index a7d03fcabf546..a502a27948e29 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -335,6 +335,7 @@ pub fn qpath_to_string(p: &hir::QPath<'_>) -> String { let segments = match *p { hir::QPath::Resolved(_, ref path) => &path.segments, 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(); From bde529fb773fa227e9bcaecd08754fd3a51b04c8 Mon Sep 17 00:00:00 2001 From: David Wood Date: Tue, 4 Aug 2020 14:24:13 +0100 Subject: [PATCH 9/9] clippy: support `QPath::LangItem` This commit updates clippy with the introduction of `QPath::LangItem` so that it still compiles. Signed-off-by: David Wood --- src/tools/clippy/clippy_lints/src/default_trait_access.rs | 2 +- src/tools/clippy/clippy_lints/src/types.rs | 1 + src/tools/clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_lints/src/utils/hir_utils.rs | 6 ++++++ src/tools/clippy/clippy_lints/src/utils/inspector.rs | 6 ++++++ src/tools/clippy/clippy_lints/src/utils/mod.rs | 5 ++++- 6 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/default_trait_access.rs b/src/tools/clippy/clippy_lints/src/default_trait_access.rs index 874e19d9e9fb3..067ea903bdd96 100644 --- a/src/tools/clippy/clippy_lints/src/default_trait_access.rs +++ b/src/tools/clippy/clippy_lints/src/default_trait_access.rs @@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess { ); } }, - QPath::TypeRelative(..) => {}, + QPath::TypeRelative(..) | QPath::LangItem(..) => {}, } } } diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs index c3dea44752133..d1a7886a47eff 100644 --- a/src/tools/clippy/clippy_lints/src/types.rs +++ b/src/tools/clippy/clippy_lints/src/types.rs @@ -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), diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 128fa87a16212..01850bb3df6ad 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -760,5 +760,6 @@ fn print_path(path: &QPath<'_>, first: &mut bool) { }, ref other => print!("/* unimplemented: {:?}*/", other), }, + QPath::LangItem(lang_item, ..) => print!("#[lang = \"{}\"]", lang_item.name()), } } diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs index 28fb6ed12a05a..0ce402ee7fa86 100644 --- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs @@ -601,6 +601,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { QPath::TypeRelative(_, ref path) => { 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); } @@ -710,6 +713,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_ty(ty); segment.ident.name.hash(&mut self.s); }, + QPath::LangItem(lang_item, ..) => { + lang_item.hash(&mut self.s); + } }, TyKind::OpaqueDef(_, arg_list) => { self.hash_generic_args(arg_list); diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index d8fa1fa278e29..4701a3f26e6f7 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -266,6 +266,9 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { println!("{}Relative Path, {:?}", ind, ty); 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) => { println!("{}AddrOf", ind); println!("kind: {:?}", kind); @@ -488,6 +491,9 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) { println!("{}Relative Path, {:?}", ind, ty); 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) => { println!("{}Tuple", ind); if let Some(dot_position) = opt_dots_position { diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 223628cc610da..d3c99eaa9cf9c 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -163,6 +163,7 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> { match *path { QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"), QPath::TypeRelative(_, ref seg) => seg, + QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"), } } @@ -170,6 +171,7 @@ pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment match *path { QPath::Resolved(_, ref path) => path.segments.get(0), QPath::TypeRelative(_, ref seg) => Some(seg), + QPath::LangItem(..) => panic!("single_segment_path: lang item has no path segments"), } } @@ -196,6 +198,7 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { }, _ => false, }, + QPath::LangItem(..) => panic!("match_qpath: lang item has no path segments"), } } @@ -277,7 +280,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option { pub fn qpath_res(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res { match qpath { 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()) { cx.tcx.typeck(id.owner.to_def_id().expect_local()).qpath_res(qpath, id) } else {