Skip to content
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

Refactor ty::ClosureKind related stuff #104732

Merged
merged 6 commits into from
Nov 28, 2022
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
6 changes: 3 additions & 3 deletions compiler/rustc_hir_typeck/src/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
let kind = object_type
.principal_def_id()
.and_then(|did| self.tcx.fn_trait_kind_from_lang_item(did));
.and_then(|did| self.tcx.fn_trait_kind_from_def_id(did));
(sig, kind)
}
ty::Infer(ty::TyVar(vid)) => self.deduce_signature_from_predicates(
Expand Down Expand Up @@ -235,7 +235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => None,
};
if let Some(closure_kind) =
trait_def_id.and_then(|def_id| self.tcx.fn_trait_kind_from_lang_item(def_id))
trait_def_id.and_then(|def_id| self.tcx.fn_trait_kind_from_def_id(def_id))
{
expected_kind = Some(
expected_kind
Expand Down Expand Up @@ -263,7 +263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let trait_def_id = projection.trait_def_id(tcx);

let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
let is_fn = tcx.is_fn_trait(trait_def_id);
let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
let is_gen = gen_trait == trait_def_id;
if !is_fn && !is_gen {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2089,7 +2089,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id)
&& let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id)
// Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce"
&& let Some(call_kind) = ty::ClosureKind::from_def_id(self.tcx, maybe_trait_def_id)
&& let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id)
&& let Some(callee_ty) = callee_ty
{
let callee_ty = callee_ty.peel_refs();
Expand All @@ -2115,7 +2115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) = predicate.kind().skip_binder()
&& pred.self_ty().peel_refs() == callee_ty
&& ty::ClosureKind::from_def_id(self.tcx, pred.def_id()).is_some()
&& self.tcx.is_fn_trait(pred.def_id())
{
err.span_note(span, "callable defined here");
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,10 +399,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);

if self_ty.value.is_closure()
&& self
.tcx()
.fn_trait_kind_from_lang_item(expected_trait_ref.value.def_id)
.is_some()
&& self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
{
let closure_sig = self_ty.map(|closure| {
if let ty::Closure(_, substs) = closure.kind() {
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_middle/src/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ impl<'tcx> TyCtxt<'tcx> {
})
}

pub fn fn_trait_kind_from_lang_item(self, id: DefId) -> Option<ty::ClosureKind> {
/// Given a [`DefId`] of a [`Fn`], [`FnMut`] or [`FnOnce`] traits,
/// returns a corresponding [`ty::ClosureKind`].
/// For any other [`DefId`] return `None`.
pub fn fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> {
let items = self.lang_items();
match Some(id) {
x if x == items.fn_trait() => Some(ty::ClosureKind::Fn),
Expand All @@ -36,6 +39,11 @@ impl<'tcx> TyCtxt<'tcx> {
_ => None,
}
}

/// Returns `true` if `id` is a `DefId` of [`Fn`], [`FnMut`] or [`FnOnce`] traits.
pub fn is_fn_trait(self, id: DefId) -> bool {
self.fn_trait_kind_from_def_id(id).is_some()
}
}

/// Returns `true` if the specified `lang_item` must be present for this
Expand Down
45 changes: 14 additions & 31 deletions compiler/rustc_middle/src/ty/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,39 +97,12 @@ impl<'tcx> ClosureKind {
/// Returns `true` if a type that impls this closure kind
/// must also implement `other`.
pub fn extends(self, other: ty::ClosureKind) -> bool {
matches!(
(self, other),
(ClosureKind::Fn, ClosureKind::Fn)
| (ClosureKind::Fn, ClosureKind::FnMut)
| (ClosureKind::Fn, ClosureKind::FnOnce)
| (ClosureKind::FnMut, ClosureKind::FnMut)
| (ClosureKind::FnMut, ClosureKind::FnOnce)
| (ClosureKind::FnOnce, ClosureKind::FnOnce)
)
}

/// Returns the representative scalar type for this closure kind.
/// See `Ty::to_opt_closure_kind` for more details.
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self {
ClosureKind::Fn => tcx.types.i8,
ClosureKind::FnMut => tcx.types.i16,
ClosureKind::FnOnce => tcx.types.i32,
}
}

pub fn from_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ClosureKind> {
if Some(def_id) == tcx.lang_items().fn_once_trait() {
Some(ClosureKind::FnOnce)
} else if Some(def_id) == tcx.lang_items().fn_mut_trait() {
Some(ClosureKind::FnMut)
} else if Some(def_id) == tcx.lang_items().fn_trait() {
Some(ClosureKind::Fn)
} else {
None
}
self <= other
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved
}

/// Converts `self` to a [`DefId`] of the corresponding trait.
///
/// Note: the inverse of this function is [`TyCtxt::fn_trait_kind_from_def_id`].
pub fn to_def_id(&self, tcx: TyCtxt<'_>) -> DefId {
tcx.require_lang_item(
match self {
Expand All @@ -140,6 +113,16 @@ impl<'tcx> ClosureKind {
None,
)
}

/// Returns the representative scalar type for this closure kind.
/// See `Ty::to_opt_closure_kind` for more details.
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self {
ClosureKind::Fn => tcx.types.i8,
ClosureKind::FnMut => tcx.types.i16,
ClosureKind::FnOnce => tcx.types.i32,
}
}
}

/// A composite describing a `Place` that is captured by a closure.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,7 @@ pub trait PrettyPrinter<'tcx>:
let mut resugared = false;

// Special-case `Fn(...) -> ...` and re-sugar it.
let fn_trait_kind = cx.tcx().fn_trait_kind_from_lang_item(principal.def_id);
let fn_trait_kind = cx.tcx().fn_trait_kind_from_def_id(principal.def_id);
if !cx.should_print_verbose() && fn_trait_kind.is_some() {
if let ty::Tuple(tys) = principal.substs.type_at(0).kind() {
let mut projections = predicates.projection_bounds();
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2114,8 +2114,7 @@ impl<'tcx> Ty<'tcx> {
/// parameter. This is kind of a phantom type, except that the
/// most convenient thing for us to are the integral types. This
/// function converts such a special type into the closure
/// kind. To go the other way, use
/// `tcx.closure_kind_ty(closure_kind)`.
/// kind. To go the other way, use `closure_kind.to_ty(tcx)`.
///
/// Note that during type checking, we use an inference variable
/// to represent the closure kind, because it has not yet been
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
}
ty::InstanceDef::FnPtrShim(def_id, ty) => {
let trait_ = tcx.trait_of_item(def_id).unwrap();
let adjustment = match tcx.fn_trait_kind_from_lang_item(trait_) {
let adjustment = match tcx.fn_trait_kind_from_def_id(trait_) {
Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
Some(ty::ClosureKind::FnMut | ty::ClosureKind::Fn) => Adjustment::Deref,
None => bug!("fn pointer {:?} is not an fn", ty),
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,8 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
ocx.register_obligation(obligation);
if ocx.select_all_or_error().is_empty() {
return Ok((
ty::ClosureKind::from_def_id(self.tcx, trait_def_id)
self.tcx
.fn_trait_kind_from_def_id(trait_def_id)
.expect("expected to map DefId to ClosureKind"),
ty.rebind(self.resolve_vars_if_possible(var)),
));
Expand Down Expand Up @@ -686,7 +687,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
ObligationCauseCode::BindingObligation(def_id, _)
| ObligationCauseCode::ItemObligation(def_id)
if ty::ClosureKind::from_def_id(tcx, *def_id).is_some() =>
if tcx.is_fn_trait(*def_id) =>
{
err.code(rustc_errors::error_code!(E0059));
err.set_primary_message(format!(
Expand Down Expand Up @@ -846,8 +847,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
}

let is_fn_trait =
ty::ClosureKind::from_def_id(tcx, trait_ref.def_id()).is_some();
let is_fn_trait = tcx.is_fn_trait(trait_ref.def_id());
let is_target_feature_fn = if let ty::FnDef(def_id, _) =
*trait_ref.skip_binder().self_ty().kind()
{
Expand Down Expand Up @@ -877,7 +877,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
// to implement.
let selected_kind =
ty::ClosureKind::from_def_id(self.tcx, trait_ref.def_id())
self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id())
.expect("expected to map DefId to ClosureKind");
if !implemented_kind.extends(selected_kind) {
err.note(
Expand Down Expand Up @@ -2155,7 +2155,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if generics.params.iter().any(|p| p.name != kw::SelfUpper)
&& !snippet.ends_with('>')
&& !generics.has_impl_trait()
&& !self.tcx.fn_trait_kind_from_lang_item(def_id).is_some()
&& !self.tcx.is_fn_trait(def_id)
{
// FIXME: To avoid spurious suggestions in functions where type arguments
// where already supplied, we check the snippet to make sure it doesn't
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1679,9 +1679,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
) -> Ty<'tcx> {
let inputs = trait_ref.skip_binder().substs.type_at(1);
let sig = match inputs.kind() {
ty::Tuple(inputs)
if infcx.tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() =>
{
ty::Tuple(inputs) if infcx.tcx.is_fn_trait(trait_ref.def_id()) => {
infcx.tcx.mk_fn_sig(
inputs.iter(),
infcx.next_ty_var(TypeVariableOrigin {
Expand Down Expand Up @@ -1752,7 +1750,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&& let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
&& let Some(pred) = predicates.predicates.get(*idx)
&& let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder()
&& ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id()).is_some()
&& self.tcx.is_fn_trait(trait_pred.def_id())
{
let expected_self =
self.tcx.anonymize_late_bound_regions(pred.kind().rebind(trait_pred.self_ty()));
Expand All @@ -1766,8 +1764,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.enumerate()
.find(|(other_idx, (pred, _))| match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))
if ty::ClosureKind::from_def_id(self.tcx, trait_pred.def_id())
.is_some()
if self.tcx.is_fn_trait(trait_pred.def_id())
&& other_idx != idx
// Make sure that the self type matches
// (i.e. constraining this closure)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
let Some(kind) = self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) else {
let Some(kind) = self.tcx().fn_trait_kind_from_def_id(obligation.predicate.def_id()) else {
return;
};

Expand Down Expand Up @@ -489,7 +489,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidates: &mut SelectionCandidateSet<'tcx>,
) {
// We provide impl of all fn traits for fn pointers.
if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() {
if !self.tcx().is_fn_trait(obligation.predicate.def_id()) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let kind = self
.tcx()
.fn_trait_kind_from_lang_item(obligation.predicate.def_id())
.fn_trait_kind_from_def_id(obligation.predicate.def_id())
.unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation));

// Okay to skip binder because the substs on closure types never
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ty_utils/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ fn resolve_associated_item<'tcx>(
substs: future_data.substs,
}),
traits::ImplSource::Closure(closure_data) => {
let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap();
let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
Instance::resolve_closure(
tcx,
closure_data.closure_def_id,
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/clean/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ fn external_generic_args<'tcx>(
) -> GenericArgs {
let args = substs_to_args(cx, substs, has_self);

if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() {
if cx.tcx.fn_trait_kind_from_def_id(did).is_some() {
let inputs =
// The trait's first substitution is the one after self, if there is one.
match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() {
Expand Down