diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 1ff961a90890c..c17af666eb9fe 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -19,7 +19,7 @@ use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::ArgKind; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; -use std::cmp; +use rustc_type_ir::ClosureKind; use std::iter; use std::ops::ControlFlow; @@ -437,10 +437,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(found_kind) = found_kind { - expected_kind = Some( - expected_kind - .map_or_else(|| found_kind, |current| cmp::min(current, found_kind)), - ); + // always use the closure kind that is more permissive. + match (expected_kind, found_kind) { + (None, _) => expected_kind = Some(found_kind), + (Some(ClosureKind::FnMut), ClosureKind::Fn) => { + expected_kind = Some(ClosureKind::Fn) + } + (Some(ClosureKind::FnOnce), ClosureKind::Fn | ClosureKind::FnMut) => { + expected_kind = Some(found_kind) + } + _ => {} + } } } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 9fc8d418f5b25..814c3629b08fa 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -30,7 +30,7 @@ pub struct Instance<'tcx> { pub args: GenericArgsRef<'tcx>, } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub enum InstanceDef<'tcx> { /// A user-defined callable item. diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 381681fb1f416..2816bcc888b0c 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -7,6 +7,7 @@ use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt}; use rustc_span::sym; use rustc_trait_selection::traits; +use rustc_type_ir::ClosureKind; use traits::{translate_args, Reveal}; use crate::errors::UnexpectedFnPtrAssociatedItem; @@ -296,23 +297,25 @@ fn resolve_associated_item<'tcx>( { match *rcvr_args.type_at(0).kind() { ty::CoroutineClosure(coroutine_closure_def_id, args) => { - // If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure, - // or `AsyncFnOnce` for a by-mut closure, then construct a new body that - // has the right return types. - // - // Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs - // to have its input and output types fixed (`&mut self` and returning - // `i16` coroutine kind). - if target_kind > args.as_coroutine_closure().kind() { - Some(Instance { - def: ty::InstanceDef::ConstructCoroutineInClosureShim { - coroutine_closure_def_id, - target_kind, - }, - args, - }) - } else { - Some(Instance::new(coroutine_closure_def_id, args)) + match (target_kind, args.as_coroutine_closure().kind()) { + (ClosureKind::FnOnce | ClosureKind::FnMut, ClosureKind::Fn) + | (ClosureKind::FnOnce, ClosureKind::FnMut) => { + // If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure, + // or `AsyncFnOnce` for a by-mut closure, then construct a new body that + // has the right return types. + // + // Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs + // to have its input and output types fixed (`&mut self` and returning + // `i16` coroutine kind). + Some(Instance { + def: ty::InstanceDef::ConstructCoroutineInClosureShim { + coroutine_closure_def_id, + target_kind, + }, + args, + }) + } + _ => Some(Instance::new(coroutine_closure_def_id, args)), } } ty::Closure(closure_def_id, args) => { diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 2ded1b956e519..c01baa58ae784 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -369,12 +369,9 @@ rustc_index::newtype_index! { /// /// You can get the environment type of a closure using /// `tcx.closure_env_ty()`. -#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] pub enum ClosureKind { - // Warning: Ordering is significant here! The ordering is chosen - // because the trait Fn is a subtrait of FnMut and so in turn, and - // hence we order it so that Fn < FnMut < FnOnce. Fn, FnMut, FnOnce, @@ -394,8 +391,15 @@ impl ClosureKind { /// Returns `true` if a type that impls this closure kind /// must also implement `other`. + #[rustfmt::skip] pub fn extends(self, other: ClosureKind) -> bool { - self <= other + use ClosureKind::*; + match (self, other) { + (Fn, Fn | FnMut | FnOnce) + | (FnMut, FnMut | FnOnce) + | (FnOnce, FnOnce) => true, + _ => false, + } } }