Implement associated lang items
Fixes #70718 This commit allows making associated items (e.g. associated functions and types) into lang items via the `#[lang]` attribute. This allows such items to be accessed directly, rather than by iterating over the parent item's associated items. I've added `FnOnce::Output` as a lang item, and updated one old usage to use the new lang item. The remaining uses can be updated separately.
This commit is contained in:
parent
d8ed1b03c2
commit
a13d4678fe
@ -224,6 +224,7 @@ pub trait FnMut<Args>: FnOnce<Args> {
|
||||
#[must_use = "closures are lazy and do nothing unless called"]
|
||||
pub trait FnOnce<Args> {
|
||||
/// The returned type after the call operator is used.
|
||||
#[cfg_attr(not(bootstrap), lang = "fn_once_output")]
|
||||
#[stable(feature = "fn_once_output", since = "1.12.0")]
|
||||
type Output;
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
// So you probably just want to nip down to the end.
|
||||
macro_rules! language_item_table {
|
||||
(
|
||||
$( $variant:ident, $name:expr, $method:ident, $target:path; )*
|
||||
$( $variant:ident, $name:expr, $method:ident, $target:expr; )*
|
||||
) => {
|
||||
|
||||
enum_from_u32! {
|
||||
@ -207,6 +207,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
|
||||
FnMutTraitLangItem, "fn_mut", fn_mut_trait, Target::Trait;
|
||||
FnOnceTraitLangItem, "fn_once", fn_once_trait, Target::Trait;
|
||||
|
||||
FnOnceOutputLangItem, "fn_once_output", fn_once_output, Target::AssocTy;
|
||||
|
||||
FutureTraitLangItem, "future_trait", future_trait, Target::Trait;
|
||||
GeneratorStateLangItem, "generator_state", gen_state, Target::Enum;
|
||||
GeneratorTraitLangItem, "generator", gen_trait, Target::Trait;
|
||||
|
@ -21,7 +21,10 @@
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
||||
fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
|
||||
pub(crate) fn target_from_impl_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_item: &hir::ImplItem<'_>,
|
||||
) -> Target {
|
||||
match impl_item.kind {
|
||||
hir::ImplItemKind::Const(..) => Target::AssocConst,
|
||||
hir::ImplItemKind::Fn(..) => {
|
||||
|
@ -7,17 +7,19 @@
|
||||
//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
|
||||
//! * Functions called by the compiler itself.
|
||||
|
||||
use crate::check_attr::target_from_impl_item;
|
||||
use crate::weak_lang_items;
|
||||
|
||||
use rustc_middle::middle::cstore::ExternCrate;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
use rustc_ast::ast::Attribute;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::lang_items::{extract, ITEM_REFS};
|
||||
use rustc_hir::{LangItem, LanguageItems, Target};
|
||||
use rustc_hir::{HirId, LangItem, LanguageItems, Target};
|
||||
|
||||
use rustc_middle::ty::query::Providers;
|
||||
|
||||
@ -28,12 +30,37 @@ struct LanguageItemCollector<'tcx> {
|
||||
|
||||
impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
if let Some((value, span)) = extract(&item.attrs) {
|
||||
let actual_target = Target::from_item(item);
|
||||
self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs)
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
|
||||
self.check_for_lang(
|
||||
Target::from_trait_item(trait_item),
|
||||
trait_item.hir_id,
|
||||
trait_item.attrs,
|
||||
)
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
|
||||
self.check_for_lang(
|
||||
target_from_impl_item(self.tcx, impl_item),
|
||||
impl_item.hir_id,
|
||||
impl_item.attrs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl LanguageItemCollector<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
|
||||
LanguageItemCollector { tcx, items: LanguageItems::new() }
|
||||
}
|
||||
|
||||
fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId, attrs: &[Attribute]) {
|
||||
if let Some((value, span)) = extract(&attrs) {
|
||||
match ITEM_REFS.get(&*value.as_str()).cloned() {
|
||||
// Known lang item with attribute on correct target.
|
||||
Some((item_index, expected_target)) if actual_target == expected_target => {
|
||||
let def_id = self.tcx.hir().local_def_id(item.hir_id);
|
||||
let def_id = self.tcx.hir().local_def_id(hir_id);
|
||||
self.collect_item(item_index, def_id.to_def_id());
|
||||
}
|
||||
// Known lang item with attribute on incorrect target.
|
||||
@ -71,20 +98,6 @@ fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {
|
||||
// At present, lang items are always items, not trait items.
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {
|
||||
// At present, lang items are always items, not impl items.
|
||||
}
|
||||
}
|
||||
|
||||
impl LanguageItemCollector<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
|
||||
LanguageItemCollector { tcx, items: LanguageItems::new() }
|
||||
}
|
||||
|
||||
fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
|
||||
// Check for duplicates.
|
||||
if let Some(original_def_id) = self.items.items[item_index] {
|
||||
|
@ -23,13 +23,13 @@
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem};
|
||||
use rustc_hir::lang_items::{FnOnceOutputLangItem, FnOnceTraitLangItem, GeneratorTraitLangItem};
|
||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
pub use rustc_middle::traits::Reveal;
|
||||
@ -1399,8 +1399,8 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
||||
|
||||
debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig);
|
||||
|
||||
// the `Output` associated type is declared on `FnOnce`
|
||||
let fn_once_def_id = tcx.require_lang_item(FnOnceTraitLangItem, None);
|
||||
let fn_once_output_def_id = tcx.require_lang_item(FnOnceOutputLangItem, None);
|
||||
|
||||
let predicate = super::util::closure_trait_ref_and_return_type(
|
||||
tcx,
|
||||
@ -1410,11 +1410,10 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
||||
flag,
|
||||
)
|
||||
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy::from_ref_and_name(
|
||||
tcx,
|
||||
trait_ref,
|
||||
Ident::with_dummy_span(rustc_hir::FN_OUTPUT_NAME),
|
||||
),
|
||||
projection_ty: ty::ProjectionTy {
|
||||
substs: trait_ref.substs,
|
||||
item_def_id: fn_once_output_def_id,
|
||||
},
|
||||
ty: ret_type,
|
||||
});
|
||||
|
||||
|
21
src/test/ui/assoc-lang-items.rs
Normal file
21
src/test/ui/assoc-lang-items.rs
Normal file
@ -0,0 +1,21 @@
|
||||
#![feature(lang_items)]
|
||||
|
||||
trait Foo {
|
||||
#[lang = "dummy_lang_item_1"] //~ ERROR definition
|
||||
fn foo() {}
|
||||
|
||||
#[lang = "dummy_lang_item_2"] //~ ERROR definition
|
||||
fn bar();
|
||||
|
||||
#[lang = "dummy_lang_item_3"] //~ ERROR definition
|
||||
type MyType;
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Bar {
|
||||
#[lang = "dummy_lang_item_4"] //~ ERROR definition
|
||||
fn test() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
27
src/test/ui/assoc-lang-items.stderr
Normal file
27
src/test/ui/assoc-lang-items.stderr
Normal file
@ -0,0 +1,27 @@
|
||||
error[E0522]: definition of an unknown language item: `dummy_lang_item_1`
|
||||
--> $DIR/assoc-lang-items.rs:4:5
|
||||
|
|
||||
LL | #[lang = "dummy_lang_item_1"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_1`
|
||||
|
||||
error[E0522]: definition of an unknown language item: `dummy_lang_item_2`
|
||||
--> $DIR/assoc-lang-items.rs:7:5
|
||||
|
|
||||
LL | #[lang = "dummy_lang_item_2"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_2`
|
||||
|
||||
error[E0522]: definition of an unknown language item: `dummy_lang_item_3`
|
||||
--> $DIR/assoc-lang-items.rs:10:5
|
||||
|
|
||||
LL | #[lang = "dummy_lang_item_3"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_3`
|
||||
|
||||
error[E0522]: definition of an unknown language item: `dummy_lang_item_4`
|
||||
--> $DIR/assoc-lang-items.rs:17:5
|
||||
|
|
||||
LL | #[lang = "dummy_lang_item_4"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_4`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0522`.
|
Loading…
Reference in New Issue
Block a user