Rust: Make lang items private

Created on 15 May 2020  路  16Comments  路  Source: rust-lang/rust

72170 and #72216 put some effort in to try and prevent some potential ICEs that can occur in #![no_core] due to how we currently reference lang items.

@oli-obk pointed out:

Oh, that's a very good idea. I wonder if we can make lang_items private at some point and just have sensible wrappers like require_lang_item.

I'm opening this issue to start a discussion about how we could take this forward.


A-lang-item C-enhancement T-compiler

All 16 comments

Here are my thoughts at the moment:

  • The main thing we want to avoid is calling tcx.lang_items().<item>().unwrap() as in #![no_core] this is a hard panic
  • Using tcx.require_lang_item(<Item>, span) trivially resolves this
  • Ideally we would just remove all uses of tcx.lang_items().<item>() and remove lang_items for the type context's public API
  • There's a problem in that the following is a pattern used throughout the compiler in diagnostic generation:
if Some(def_id) == tcx.lang_items().<item>() {
    // some smart diagnostic
}
  • This can't be swapped for def_id == tcx.require_lang_item(<Item>, span) because we don't want to trigger a fatal error if the lang item isn't found, we just don't want to emit the diagnostic

My feeling at the moment is that something along the lines of tcx.is_lang_item(<Item>, def_id) is the tidiest way to solve this, but obviously this is going to touch a lot of code so I thought it was worth a discussion.

If we want to make it clear that this should only be used for diagnostics, we could name the function check_lang_item_for_diagnostic or sth similar. It's a mouth full, but at least this means noone will mis-use it. Another alternative is to make it a method on DiagnosticBuilder that takes a closure and only invokes the closure if the DefId is the specified lang item. This way it definitely can't be mis-used and is on the right API.

The easiest way might be to add tcx.get_lang_item(LangItem) -> Option<DefId> with a doc comment recommending require_lang_item in case the lang item is required.

I think we should use a custom return type, not Option, for the result of tcx.lang_items().<item>(). It would have a require method that takes a span and a TyCtxt and works the same way as require_lang_item, plus an exists method that returns a bool. This makes it much harder to misuse the API and you can still match on it to extract the def_id.

The easiest way might be to add tcx.get_lang_item(LangItem) -> Option<DefId> with a doc comment recommending require_lang_item in case the lang item is required.

I think we'd have to be careful with this as I imagine this is the sort of thing that will slip through almost all code reviews

I think we should use a custom return type, not Option, for the result of tcx.lang_items().<item(>). It would have a require method that takes a span and works the same way as require_lang_item and an exists method that converts to a bool. This makes it much harder to misuse the API.

I really like this idea - although to make sure lang_items stays private, we'd probably want to move it up a level. Something like tcx.query_lang_item(<Item>) that returns the new opaque option.

We could just bolt a is_def_id(def_id) method on the API for the opaque option then as well to deal with the diagnostic pattern.

to use a modification like that to the DiagnosticBuilder API might be more trouble than it's worth...

Oh wow... that !is_unsize definitely kills that idea, agreed.

I really like this idea - although to make sure lang_items stays private, we'd probably want to move it up a level. Something like tcx.query_lang_item(<Item>) that returns the new opaque option.

I think the suggested idea is to make the LangItems type's functions all private, so we don't need to make lang_items private, as we can just add the is and expect functions to it as public functions and expose no further API

Ahh okay I misunderstood... So the change would be something like:

  • introducing an opaque option for lang items
  • updating the current lang_items API to return the new wrapper in place of the old options
  • adding is and expect methods for the new wrapper
  • reimplementing the current methods like tcx.require_lang_item to use the new API
  • updating uses of the Some(def_id) == ... pattern to use is

I think the suggested idea is to make the LangItems type's functions all private, so we don't need to make lang_items private,

That's what I had in mind, yes. I like avoiding the need for imports (e.g., FutureTraitLangItem) when possible.

Okay yeah - I really like that, I'll have a go at implementing it then

@rustbot claim

(Side note: discussing on the issue seems fine, but this seems like an MCP-worthy thing.)

@nikomatsakis I spoke to @oli-obk about whether an MCP was necessary before I opened this issue but I don鈥檛 think either of us appreciated the amount of code this was going to effect and therefore didn鈥檛 think it was necessary. I don鈥檛 really know anything about the MCP process as I鈥檝e been out of the loop for a while but I鈥檓 more than happy to learn about it and take this down that route.

Triage: Hi, are you still working on this issue @doctorn?

@rustbot release-assignment

Was this page helpful?
0 / 5 - 0 ratings