Skip to content

Commit 229e5b2

Browse files
committed
Auto merge of #72559 - Aaron1011:feature/assoc-lang-items, r=oli-obk
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.
2 parents 67100f6 + a13d467 commit 229e5b2

File tree

7 files changed

+94
-28
lines changed

7 files changed

+94
-28
lines changed

src/libcore/ops/function.rs

+1
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ pub trait FnMut<Args>: FnOnce<Args> {
224224
#[must_use = "closures are lazy and do nothing unless called"]
225225
pub trait FnOnce<Args> {
226226
/// The returned type after the call operator is used.
227+
#[cfg_attr(not(bootstrap), lang = "fn_once_output")]
227228
#[stable(feature = "fn_once_output", since = "1.12.0")]
228229
type Output;
229230

src/librustc_hir/lang_items.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use lazy_static::lazy_static;
2525
// So you probably just want to nip down to the end.
2626
macro_rules! language_item_table {
2727
(
28-
$( $variant:ident, $name:expr, $method:ident, $target:path; )*
28+
$( $variant:ident, $name:expr, $method:ident, $target:expr; )*
2929
) => {
3030

3131
enum_from_u32! {
@@ -207,6 +207,8 @@ language_item_table! {
207207
FnMutTraitLangItem, "fn_mut", fn_mut_trait, Target::Trait;
208208
FnOnceTraitLangItem, "fn_once", fn_once_trait, Target::Trait;
209209

210+
FnOnceOutputLangItem, "fn_once_output", fn_once_output, Target::AssocTy;
211+
210212
FutureTraitLangItem, "future_trait", future_trait, Target::Trait;
211213
GeneratorStateLangItem, "generator_state", gen_state, Target::Enum;
212214
GeneratorTraitLangItem, "generator", gen_trait, Target::Trait;

src/librustc_passes/check_attr.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ use rustc_session::parse::feature_err;
2121
use rustc_span::symbol::sym;
2222
use rustc_span::Span;
2323

24-
fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
24+
pub(crate) fn target_from_impl_item<'tcx>(
25+
tcx: TyCtxt<'tcx>,
26+
impl_item: &hir::ImplItem<'_>,
27+
) -> Target {
2528
match impl_item.kind {
2629
hir::ImplItemKind::Const(..) => Target::AssocConst,
2730
hir::ImplItemKind::Fn(..) => {

src/librustc_passes/lang_items.rs

+31-18
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,19 @@
77
//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
88
//! * Functions called by the compiler itself.
99
10+
use crate::check_attr::target_from_impl_item;
1011
use crate::weak_lang_items;
1112

1213
use rustc_middle::middle::cstore::ExternCrate;
1314
use rustc_middle::ty::TyCtxt;
1415

16+
use rustc_ast::ast::Attribute;
1517
use rustc_errors::struct_span_err;
1618
use rustc_hir as hir;
1719
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
1820
use rustc_hir::itemlikevisit::ItemLikeVisitor;
1921
use rustc_hir::lang_items::{extract, ITEM_REFS};
20-
use rustc_hir::{LangItem, LanguageItems, Target};
22+
use rustc_hir::{HirId, LangItem, LanguageItems, Target};
2123

2224
use rustc_middle::ty::query::Providers;
2325

@@ -28,12 +30,37 @@ struct LanguageItemCollector<'tcx> {
2830

2931
impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
3032
fn visit_item(&mut self, item: &hir::Item<'_>) {
31-
if let Some((value, span)) = extract(&item.attrs) {
32-
let actual_target = Target::from_item(item);
33+
self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs)
34+
}
35+
36+
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
37+
self.check_for_lang(
38+
Target::from_trait_item(trait_item),
39+
trait_item.hir_id,
40+
trait_item.attrs,
41+
)
42+
}
43+
44+
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
45+
self.check_for_lang(
46+
target_from_impl_item(self.tcx, impl_item),
47+
impl_item.hir_id,
48+
impl_item.attrs,
49+
)
50+
}
51+
}
52+
53+
impl LanguageItemCollector<'tcx> {
54+
fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
55+
LanguageItemCollector { tcx, items: LanguageItems::new() }
56+
}
57+
58+
fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId, attrs: &[Attribute]) {
59+
if let Some((value, span)) = extract(&attrs) {
3360
match ITEM_REFS.get(&*value.as_str()).cloned() {
3461
// Known lang item with attribute on correct target.
3562
Some((item_index, expected_target)) if actual_target == expected_target => {
36-
let def_id = self.tcx.hir().local_def_id(item.hir_id);
63+
let def_id = self.tcx.hir().local_def_id(hir_id);
3764
self.collect_item(item_index, def_id.to_def_id());
3865
}
3966
// Known lang item with attribute on incorrect target.
@@ -71,20 +98,6 @@ impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
7198
}
7299
}
73100

74-
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {
75-
// At present, lang items are always items, not trait items.
76-
}
77-
78-
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {
79-
// At present, lang items are always items, not impl items.
80-
}
81-
}
82-
83-
impl LanguageItemCollector<'tcx> {
84-
fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
85-
LanguageItemCollector { tcx, items: LanguageItems::new() }
86-
}
87-
88101
fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
89102
// Check for duplicates.
90103
if let Some(original_def_id) = self.items.items[item_index] {

src/librustc_trait_selection/traits/project.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ use crate::traits::error_reporting::InferCtxtExt;
2323
use rustc_data_structures::stack::ensure_sufficient_stack;
2424
use rustc_errors::ErrorReported;
2525
use rustc_hir::def_id::DefId;
26-
use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem};
26+
use rustc_hir::lang_items::{FnOnceOutputLangItem, FnOnceTraitLangItem, GeneratorTraitLangItem};
2727
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
2828
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
2929
use rustc_middle::ty::subst::Subst;
3030
use rustc_middle::ty::util::IntTypeExt;
3131
use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
32-
use rustc_span::symbol::{sym, Ident};
32+
use rustc_span::symbol::sym;
3333
use rustc_span::DUMMY_SP;
3434

3535
pub use rustc_middle::traits::Reveal;
@@ -1399,8 +1399,8 @@ fn confirm_callable_candidate<'cx, 'tcx>(
13991399

14001400
debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig);
14011401

1402-
// the `Output` associated type is declared on `FnOnce`
14031402
let fn_once_def_id = tcx.require_lang_item(FnOnceTraitLangItem, None);
1403+
let fn_once_output_def_id = tcx.require_lang_item(FnOnceOutputLangItem, None);
14041404

14051405
let predicate = super::util::closure_trait_ref_and_return_type(
14061406
tcx,
@@ -1410,11 +1410,10 @@ fn confirm_callable_candidate<'cx, 'tcx>(
14101410
flag,
14111411
)
14121412
.map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
1413-
projection_ty: ty::ProjectionTy::from_ref_and_name(
1414-
tcx,
1415-
trait_ref,
1416-
Ident::with_dummy_span(rustc_hir::FN_OUTPUT_NAME),
1417-
),
1413+
projection_ty: ty::ProjectionTy {
1414+
substs: trait_ref.substs,
1415+
item_def_id: fn_once_output_def_id,
1416+
},
14181417
ty: ret_type,
14191418
});
14201419

src/test/ui/assoc-lang-items.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![feature(lang_items)]
2+
3+
trait Foo {
4+
#[lang = "dummy_lang_item_1"] //~ ERROR definition
5+
fn foo() {}
6+
7+
#[lang = "dummy_lang_item_2"] //~ ERROR definition
8+
fn bar();
9+
10+
#[lang = "dummy_lang_item_3"] //~ ERROR definition
11+
type MyType;
12+
}
13+
14+
struct Bar;
15+
16+
impl Bar {
17+
#[lang = "dummy_lang_item_4"] //~ ERROR definition
18+
fn test() {}
19+
}
20+
21+
fn main() {}

src/test/ui/assoc-lang-items.stderr

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0522]: definition of an unknown language item: `dummy_lang_item_1`
2+
--> $DIR/assoc-lang-items.rs:4:5
3+
|
4+
LL | #[lang = "dummy_lang_item_1"]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_1`
6+
7+
error[E0522]: definition of an unknown language item: `dummy_lang_item_2`
8+
--> $DIR/assoc-lang-items.rs:7:5
9+
|
10+
LL | #[lang = "dummy_lang_item_2"]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_2`
12+
13+
error[E0522]: definition of an unknown language item: `dummy_lang_item_3`
14+
--> $DIR/assoc-lang-items.rs:10:5
15+
|
16+
LL | #[lang = "dummy_lang_item_3"]
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_3`
18+
19+
error[E0522]: definition of an unknown language item: `dummy_lang_item_4`
20+
--> $DIR/assoc-lang-items.rs:17:5
21+
|
22+
LL | #[lang = "dummy_lang_item_4"]
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition of unknown language item `dummy_lang_item_4`
24+
25+
error: aborting due to 4 previous errors
26+
27+
For more information about this error, try `rustc --explain E0522`.

0 commit comments

Comments
 (0)