Skip to content

Implement associated lang items #72559

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libcore/ops/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
4 changes: 3 additions & 1 deletion src/librustc_hir/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use lazy_static::lazy_static;
// 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! {
Expand Down Expand Up @@ -207,6 +207,8 @@ language_item_table! {
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;
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_passes/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::Span;

fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in the same crate, so you could just make it public instead of moving it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it was better to be able to consistently use Target::from_[type]

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(..) => {
Expand Down
49 changes: 31 additions & 18 deletions src/librustc_passes/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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.
Expand Down Expand Up @@ -71,20 +98,6 @@ impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
}
}

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] {
Expand Down
15 changes: 7 additions & 8 deletions src/librustc_trait_selection/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ use crate::traits::error_reporting::InferCtxtExt;
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;
Expand Down Expand Up @@ -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,
Expand All @@ -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,
});

Expand Down
21 changes: 21 additions & 0 deletions src/test/ui/assoc-lang-items.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 27 additions & 0 deletions src/test/ui/assoc-lang-items.stderr
Original file line number Diff line number Diff line change
@@ -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`.