From 1297cb7f37bc37c6154c0fa4fcf23150c7a80548 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 3 Jul 2021 18:32:26 -0400 Subject: [PATCH 01/10] add test case --- src/test/ui/async-await/issue-84841.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/test/ui/async-await/issue-84841.rs diff --git a/src/test/ui/async-await/issue-84841.rs b/src/test/ui/async-await/issue-84841.rs new file mode 100644 index 00000000000..23367788323 --- /dev/null +++ b/src/test/ui/async-await/issue-84841.rs @@ -0,0 +1,10 @@ +// edition:2018 + +async fn main() { + // Adding an .await here avoids the ICE + test()?; +} + +// Removing the const generic parameter here avoids the ICE +async fn test() { +} From 6f4b539a62f44b64d6db3054a4c2b9c3a5ad09f3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 3 Jul 2021 22:15:32 -0400 Subject: [PATCH 02/10] introduce helper function --- .../src/ty/normalize_erasing_regions.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index a4f736654af..7c8bc0f252f 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -88,23 +88,32 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> { param_env: ty::ParamEnv<'tcx>, } +impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { + fn normalize_generic_arg_after_erasing_regions( + &self, + arg: ty::GenericArg<'tcx>, + ) -> ty::GenericArg<'tcx> { + let arg = self.param_env.and(arg); + self.tcx.normalize_generic_arg_after_erasing_regions(arg) + } +} + impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - let arg = self.param_env.and(ty.into()); - self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_ty() + self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty() } fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - let arg = self.param_env.and(c.into()); - self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_const() + self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const() } #[inline] fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { + // FIXME: This *probalby* needs canonicalization too! let arg = self.param_env.and(c); self.tcx.normalize_mir_const_after_erasing_regions(arg) } From 26f7030b16716712070d04ad938e9762b8756f7f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jul 2021 11:09:32 -0400 Subject: [PATCH 03/10] remove unused Option --- .../src/infer/canonical/canonicalizer.rs | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index c68705da413..ac953f4305c 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -46,13 +46,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { { self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed); - Canonicalizer::canonicalize( - value, - Some(self), - self.tcx, - &CanonicalizeAllFreeRegions, - query_state, - ) + Canonicalizer::canonicalize(value, self, self.tcx, &CanonicalizeAllFreeRegions, query_state) } /// Canonicalizes a query *response* `V`. When we canonicalize a @@ -87,7 +81,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let mut query_state = OriginalQueryValues::default(); Canonicalizer::canonicalize( value, - Some(self), + self, self.tcx, &CanonicalizeQueryResponse, &mut query_state, @@ -101,7 +95,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let mut query_state = OriginalQueryValues::default(); Canonicalizer::canonicalize( value, - Some(self), + self, self.tcx, &CanonicalizeUserTypeAnnotation, &mut query_state, @@ -133,7 +127,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { Canonicalizer::canonicalize( value, - Some(self), + self, self.tcx, &CanonicalizeFreeRegionsOtherThanStatic, query_state, @@ -275,7 +269,7 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic { } struct Canonicalizer<'cx, 'tcx> { - infcx: Option<&'cx InferCtxt<'cx, 'tcx>>, + infcx: &'cx InferCtxt<'cx, 'tcx>, tcx: TyCtxt<'tcx>, variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>, query_state: &'cx mut OriginalQueryValues<'tcx>, @@ -316,7 +310,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { ty::ReVar(vid) => { let resolved_vid = self .infcx - .unwrap() .inner .borrow_mut() .unwrap_region_constraints() @@ -343,7 +336,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { match *t.kind() { ty::Infer(ty::TyVar(vid)) => { debug!("canonical: type var found with vid {:?}", vid); - match self.infcx.unwrap().probe_ty_var(vid) { + match self.infcx.probe_ty_var(vid) { // `t` could be a float / int variable; canonicalize that instead. Ok(t) => { debug!("(resolved to {:?})", t); @@ -429,7 +422,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { match ct.val { ty::ConstKind::Infer(InferConst::Var(vid)) => { debug!("canonical: const var found with vid {:?}", vid); - match self.infcx.unwrap().probe_const_var(vid) { + match self.infcx.probe_const_var(vid) { Ok(c) => { debug!("(resolved to {:?})", c); return self.fold_const(c); @@ -476,7 +469,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// `canonicalize_query` and `canonicalize_response`. fn canonicalize( value: V, - infcx: Option<&InferCtxt<'_, 'tcx>>, + infcx: &InferCtxt<'_, 'tcx>, tcx: TyCtxt<'tcx>, canonicalize_region_mode: &dyn CanonicalizeRegionMode, query_state: &mut OriginalQueryValues<'tcx>, @@ -610,7 +603,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// Returns the universe in which `vid` is defined. fn region_var_universe(&self, vid: ty::RegionVid) -> ty::UniverseIndex { - self.infcx.unwrap().inner.borrow_mut().unwrap_region_constraints().var_universe(vid) + self.infcx.inner.borrow_mut().unwrap_region_constraints().var_universe(vid) } /// Creates a canonical variable (with the given `info`) @@ -631,7 +624,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { /// *that*. Otherwise, create a new canonical variable for /// `ty_var`. fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo<'tcx>, ty_var: Ty<'tcx>) -> Ty<'tcx> { - let infcx = self.infcx.expect("encountered ty-var without infcx"); + let infcx = self.infcx; let bound_to = infcx.shallow_resolve(ty_var); if bound_to != ty_var { self.fold_ty(bound_to) @@ -650,7 +643,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { info: CanonicalVarInfo<'tcx>, const_var: &'tcx ty::Const<'tcx>, ) -> &'tcx ty::Const<'tcx> { - let infcx = self.infcx.expect("encountered const-var without infcx"); + let infcx = self.infcx; let bound_to = infcx.shallow_resolve(const_var); if bound_to != const_var { self.fold_const(bound_to) From 40ee019c17dc35a1681d48246b8cdd3d6563702f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jul 2021 11:26:32 -0400 Subject: [PATCH 04/10] allow inference vars in type_implements_trait --- compiler/rustc_middle/src/query/mod.rs | 15 ++++- .../diagnostics/conflict_errors.rs | 4 +- .../src/traits/error_reporting/suggestions.rs | 4 +- .../rustc_trait_selection/src/traits/mod.rs | 16 +++-- compiler/rustc_typeck/src/check/cast.rs | 15 +++-- compiler/rustc_typeck/src/check/upvar.rs | 14 +++-- src/test/ui/async-await/issue-84841.rs | 8 ++- src/test/ui/async-await/issue-84841.stderr | 28 +++++++++ src/tools/clippy/clippy_utils/src/ty.rs | 60 +++++++++++-------- 9 files changed, 118 insertions(+), 46 deletions(-) create mode 100644 src/test/ui/async-await/issue-84841.stderr diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 23ee0e05062..0986a465729 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1559,9 +1559,22 @@ rustc_queries! { desc { "evaluating trait selection obligation `{}`", goal.value } } + /// Evaluates whether the given type implements the given trait + /// in the given environment. + /// + /// The inputs are: + /// + /// - the def-id of the trait + /// - the self type + /// - the *other* type parameters of the trait, excluding the self-type + /// - the parameter environment + /// + /// FIXME. If the type, trait, or environment has inference variables, + /// this yields `EvaluatedToUnknown`. It should be refactored + /// to use canonicalization, really. query type_implements_trait( key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, ) - ) -> bool { + ) -> traits::EvaluationResult { desc { "evaluating `type_implements_trait` `{:?}`", key } } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index a0c9b43d5af..c1c875eac55 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -1331,7 +1331,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // to avoid panics if !return_ty.has_infer_types() { if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) { - if tcx.type_implements_trait((iter_trait, return_ty, ty_params, self.param_env)) + if tcx + .type_implements_trait((iter_trait, return_ty, ty_params, self.param_env)) + .must_apply_modulo_regions() { if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) { err.span_suggestion_hidden( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 5c35b515f3d..dc765f5228b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2396,7 +2396,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { normalized_ty, ); debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation); - if self.predicate_may_hold(&try_obligation) && impls_future { + if self.predicate_may_hold(&try_obligation) + && impls_future.must_apply_modulo_regions() + { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { if snippet.ends_with('?') { err.span_suggestion_verbose( diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index d65a596a827..c5c1da2d2c0 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -542,8 +542,7 @@ fn vtable_trait_first_method_offset<'tcx>( } /// Check whether a `ty` implements given trait(trait_def_id). -/// -/// NOTE: Always return `false` for a type which needs inference. +/// See query definition for details. fn type_implements_trait<'tcx>( tcx: TyCtxt<'tcx>, key: ( @@ -552,7 +551,7 @@ fn type_implements_trait<'tcx>( SubstsRef<'tcx>, ParamEnv<'tcx>, ), -) -> bool { +) -> EvaluationResult { let (trait_def_id, ty, params, param_env) = key; debug!( @@ -562,13 +561,22 @@ fn type_implements_trait<'tcx>( let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) }; + // FIXME: If there are inference variables anywhere, just give up and assume + // we don't know the answer. This works around the ICEs that would result from + // using those inference variables within the `infer_ctxt` we create below. + // Really we should be using canonicalized variables, or perhaps removing + // this query altogether. + if (trait_ref, param_env).needs_infer() { + return EvaluationResult::EvaluatedToUnknown; + } + let obligation = Obligation { cause: ObligationCause::dummy(), param_env, recursion_depth: 0, predicate: trait_ref.without_const().to_predicate(tcx), }; - tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) + tcx.infer_ctxt().enter(|infcx| infcx.evaluate_obligation_no_overflow(&obligation)) } pub fn provide(providers: &mut ty::query::Providers) { diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 3cbc3d231f8..7ff4a108dab 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -444,12 +444,15 @@ impl<'a, 'tcx> CastCheck<'tcx> { // panic otherwise. if !expr_ty.has_infer_types() && !ty.has_infer_types() - && fcx.tcx.type_implements_trait(( - from_trait, - ty, - ty_params, - fcx.param_env, - )) + && fcx + .tcx + .type_implements_trait(( + from_trait, + ty, + ty_params, + fcx.param_env, + )) + .must_apply_modulo_regions() { label = false; err.span_suggestion( diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 41b4172781c..e5f18778f43 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -961,12 +961,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_drop_defined_for_ty = |ty: Ty<'tcx>| { let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span)); let ty_params = self.tcx.mk_substs_trait(base_path_ty, &[]); - self.tcx.type_implements_trait(( - drop_trait, - ty, - ty_params, - self.tcx.param_env(closure_def_id.expect_local()), - )) + self.tcx + .type_implements_trait(( + drop_trait, + ty, + ty_params, + self.tcx.param_env(closure_def_id.expect_local()), + )) + .must_apply_modulo_regions() }; let is_drop_defined_for_ty = is_drop_defined_for_ty(base_path_ty); diff --git a/src/test/ui/async-await/issue-84841.rs b/src/test/ui/async-await/issue-84841.rs index 23367788323..ba3a1617b9c 100644 --- a/src/test/ui/async-await/issue-84841.rs +++ b/src/test/ui/async-await/issue-84841.rs @@ -1,8 +1,14 @@ // edition:2018 -async fn main() { +fn main() { + +} + +async fn foo() { // Adding an .await here avoids the ICE test()?; + //~^ ERROR the `?` operator can only be applied to values that implement `Try` + //~| ERROR the `?` operator can only be used in an async function that returns } // Removing the const generic parameter here avoids the ICE diff --git a/src/test/ui/async-await/issue-84841.stderr b/src/test/ui/async-await/issue-84841.stderr new file mode 100644 index 00000000000..170dcf581ed --- /dev/null +++ b/src/test/ui/async-await/issue-84841.stderr @@ -0,0 +1,28 @@ +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/issue-84841.rs:9:5 + | +LL | test()?; + | ^^^^^^^ the `?` operator cannot be applied to type `impl Future` + | + = help: the trait `Try` is not implemented for `impl Future` + = note: required by `branch` + +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/issue-84841.rs:9:11 + | +LL | async fn foo() { + | ________________- +LL | | // Adding an .await here avoids the ICE +LL | | test()?; + | | ^ cannot use the `?` operator in an async function that returns `()` +LL | | +LL | | +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `FromResidual<_>` is not implemented for `()` + = note: required by `from_residual` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index a92d3be5d3c..add487593c6 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -128,7 +128,9 @@ pub fn implements_trait<'tcx>( return false; } let ty_params = cx.tcx.mk_substs(ty_params.iter()); - cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) + cx.tcx + .type_implements_trait((trait_id, ty, ty_params, cx.param_env)) + .must_apply_modulo_regions() } /// Checks whether this type implements `Drop`. @@ -144,22 +146,26 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(), ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(), - ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { + ty::Slice(ty) + | ty::Array(ty, _) + | ty::RawPtr(ty::TypeAndMut { ty, .. }) + | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays is_must_use_ty(cx, *ty) - }, + } ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(ref def_id, _) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { - if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() { + if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() + { if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { return true; } } } false - }, + } ty::Dynamic(binder, _) => { for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { @@ -169,7 +175,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - }, + } _ => false, } } @@ -179,7 +185,11 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // not succeed /// Checks if `Ty` is normalizable. This function is useful /// to avoid crashes on `layout_of`. -pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { +pub fn is_normalizable<'tcx>( + cx: &LateContext<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, +) -> bool { is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default()) } @@ -199,15 +209,14 @@ fn is_normalizable_helper<'tcx>( if infcx.at(&cause, param_env).normalize(ty).is_ok() { match ty.kind() { ty::Adt(def, substs) => def.variants.iter().all(|variant| { - variant - .fields - .iter() - .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) + variant.fields.iter().all(|field| { + is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache) + }) }), _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { GenericArgKind::Type(inner_ty) if inner_ty != ty => { is_normalizable_helper(cx, param_env, inner_ty, cache) - }, + } _ => true, // if inner_ty == ty, we've already checked it }), } @@ -225,7 +234,9 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { match ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, - ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), + ty::Array(inner_type, _) | ty::Slice(inner_type) => { + is_recursively_primitive_type(inner_type) + } ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type), _ => false, } @@ -269,11 +280,7 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { /// removed. pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { - if let ty::Ref(_, ty, _) = ty.kind() { - peel(ty, count + 1) - } else { - (ty, count) - } + if let ty::Ref(_, ty, _) = ty.kind() { peel(ty, count + 1) } else { (ty, count) } } peel(ty, 0) } @@ -328,17 +335,18 @@ pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { return false; } - substs_a - .iter() - .zip(substs_b.iter()) - .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) { - (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b, + substs_a.iter().zip(substs_b.iter()).all(|(arg_a, arg_b)| { + match (arg_a.unpack(), arg_b.unpack()) { + (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => { + inner_a == inner_b + } (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => { same_type_and_consts(type_a, type_b) - }, + } _ => true, - }) - }, + } + }) + } _ => a == b, } } From 75c172246c5c558fc1451554fb2798018a23e872 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jul 2021 11:41:40 -0400 Subject: [PATCH 05/10] be conservative in has_significant_drop --- compiler/rustc_middle/src/ty/util.rs | 9 +++++ .../migrations/issue-86753.rs | 34 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/test/ui/closures/2229_closure_analysis/migrations/issue-86753.rs diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 7bf69b9e637..f0cff0e9247 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -816,6 +816,15 @@ impl<'tcx> ty::TyS<'tcx> { [component_ty] => component_ty, _ => self, }; + + // FIXME: We should be canonicalizing, or else moving this to a method of inference + // context, or *something* like that, but for now just avoid passing inference + // variables to queries that can't cope with them. Instead, conservatively + // return "true" (may change drop order). + if query_ty.needs_infer() { + return true; + } + // This doesn't depend on regions, so try to minimize distinct // query keys used. let erased = tcx.normalize_erasing_regions(param_env, query_ty); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/issue-86753.rs b/src/test/ui/closures/2229_closure_analysis/migrations/issue-86753.rs new file mode 100644 index 00000000000..fce9cac627b --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/migrations/issue-86753.rs @@ -0,0 +1,34 @@ +// edition:2018 +// check-pass + +#![warn(rust_2021_compatibility)] + +use std::future::Future; + +struct Runtime; + +impl Runtime { + pub fn block_on(&self, _future: F) -> F::Output { + unimplemented!() + } +} + +pub fn http(_func: F) +where + F: Fn() -> Fut, + Fut: Future, +{ + let rt = Runtime {}; + let srv = rt.block_on(async move { serve(move || async move { unimplemented!() }) }); + let _ = || rt.block_on(async { srv }); +} + +pub struct Server { + _marker: std::marker::PhantomData, +} + +pub fn serve(_new_service: S) -> Server { + unimplemented!() +} + +fn main() { } From 9bdfde0be460c096e8aecfdfe6c6eeac2e173fe4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jul 2021 11:43:22 -0400 Subject: [PATCH 06/10] remove some ad-hoc has_infer_types checks that aren't needed anymore --- .../diagnostics/conflict_errors.rs | 28 +++++++++---------- compiler/rustc_typeck/src/check/cast.rs | 15 +++------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index c1c875eac55..4be4372c039 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -9,7 +9,7 @@ use rustc_middle::mir::{ FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; -use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable}; +use rustc_middle::ty::{self, suggest_constraining_type_param, Ty}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -1329,20 +1329,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let return_ty = tcx.erase_regions(return_ty); // to avoid panics - if !return_ty.has_infer_types() { - if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) { - if tcx - .type_implements_trait((iter_trait, return_ty, ty_params, self.param_env)) - .must_apply_modulo_regions() - { - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) { - err.span_suggestion_hidden( - return_span, - "use `.collect()` to allocate the iterator", - format!("{}{}", snippet, ".collect::>()"), - Applicability::MaybeIncorrect, - ); - } + if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) { + if tcx + .type_implements_trait((iter_trait, return_ty, ty_params, self.param_env)) + .must_apply_modulo_regions() + { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) { + err.span_suggestion_hidden( + return_span, + "use `.collect()` to allocate the iterator", + format!("{}{}", snippet, ".collect::>()"), + Applicability::MaybeIncorrect, + ); } } } diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 7ff4a108dab..b0c25c86dd3 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -442,17 +442,10 @@ impl<'a, 'tcx> CastCheck<'tcx> { let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]); // Check for infer types because cases like `Option<{integer}>` would // panic otherwise. - if !expr_ty.has_infer_types() - && !ty.has_infer_types() - && fcx - .tcx - .type_implements_trait(( - from_trait, - ty, - ty_params, - fcx.param_env, - )) - .must_apply_modulo_regions() + if fcx + .tcx + .type_implements_trait((from_trait, ty, ty_params, fcx.param_env)) + .must_apply_modulo_regions() { label = false; err.span_suggestion( From 86a5a6520d0dca4dd5e8a463dac598f482886cb1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jul 2021 12:37:25 -0400 Subject: [PATCH 07/10] Update compiler/rustc_middle/src/ty/normalize_erasing_regions.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rémy Rakic --- compiler/rustc_middle/src/ty/normalize_erasing_regions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 7c8bc0f252f..11399506b96 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -113,7 +113,7 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> { #[inline] fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { - // FIXME: This *probalby* needs canonicalization too! + // FIXME: This *probably* needs canonicalization too! let arg = self.param_env.and(c); self.tcx.normalize_mir_const_after_erasing_regions(arg) } From 63fbefd359cb2934525b0395556b64078ac86cc9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jul 2021 12:50:28 -0400 Subject: [PATCH 08/10] tag issues with FIXME --- compiler/rustc_middle/src/ty/util.rs | 2 +- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f0cff0e9247..0a158423dc4 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -817,7 +817,7 @@ impl<'tcx> ty::TyS<'tcx> { _ => self, }; - // FIXME: We should be canonicalizing, or else moving this to a method of inference + // FIXME(#86868): We should be canonicalizing, or else moving this to a method of inference // context, or *something* like that, but for now just avoid passing inference // variables to queries that can't cope with them. Instead, conservatively // return "true" (may change drop order). diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c5c1da2d2c0..e48aab6f46f 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -561,7 +561,7 @@ fn type_implements_trait<'tcx>( let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) }; - // FIXME: If there are inference variables anywhere, just give up and assume + // FIXME(#86868): If there are inference variables anywhere, just give up and assume // we don't know the answer. This works around the ICEs that would result from // using those inference variables within the `infer_ctxt` we create below. // Really we should be using canonicalized variables, or perhaps removing From 1c1573d2a351c2d979c9500c18bfaecf5ba1c58c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jul 2021 12:50:35 -0400 Subject: [PATCH 09/10] remove outdated comment --- compiler/rustc_typeck/src/check/cast.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index b0c25c86dd3..a09fad3b6b7 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -440,8 +440,6 @@ impl<'a, 'tcx> CastCheck<'tcx> { let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let expr_ty = fcx.tcx.erase_regions(expr_ty); let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]); - // Check for infer types because cases like `Option<{integer}>` would - // panic otherwise. if fcx .tcx .type_implements_trait((from_trait, ty, ty_params, fcx.param_env)) From 492ba34a91612005336b8fbcc3cc16447ebc343a Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Jul 2021 12:50:41 -0400 Subject: [PATCH 10/10] revert broken formatting --- src/tools/clippy/clippy_utils/src/ty.rs | 56 +++++++++++-------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index add487593c6..2808fc35e2a 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -146,26 +146,22 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(), ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(), - ty::Slice(ty) - | ty::Array(ty, _) - | ty::RawPtr(ty::TypeAndMut { ty, .. }) - | ty::Ref(_, ty, _) => { + ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays is_must_use_ty(cx, *ty) - } + }, ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(ref def_id, _) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { - if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() - { + if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() { if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { return true; } } } false - } + }, ty::Dynamic(binder, _) => { for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { @@ -175,7 +171,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } } false - } + }, _ => false, } } @@ -185,11 +181,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // not succeed /// Checks if `Ty` is normalizable. This function is useful /// to avoid crashes on `layout_of`. -pub fn is_normalizable<'tcx>( - cx: &LateContext<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, -) -> bool { +pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default()) } @@ -209,14 +201,15 @@ fn is_normalizable_helper<'tcx>( if infcx.at(&cause, param_env).normalize(ty).is_ok() { match ty.kind() { ty::Adt(def, substs) => def.variants.iter().all(|variant| { - variant.fields.iter().all(|field| { - is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache) - }) + variant + .fields + .iter() + .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)) }), _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { GenericArgKind::Type(inner_ty) if inner_ty != ty => { is_normalizable_helper(cx, param_env, inner_ty, cache) - } + }, _ => true, // if inner_ty == ty, we've already checked it }), } @@ -234,9 +227,7 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool { match ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true, ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true, - ty::Array(inner_type, _) | ty::Slice(inner_type) => { - is_recursively_primitive_type(inner_type) - } + ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type), ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type), _ => false, } @@ -280,7 +271,11 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool { /// removed. pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) { - if let ty::Ref(_, ty, _) = ty.kind() { peel(ty, count + 1) } else { (ty, count) } + if let ty::Ref(_, ty, _) = ty.kind() { + peel(ty, count + 1) + } else { + (ty, count) + } } peel(ty, 0) } @@ -335,18 +330,17 @@ pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { return false; } - substs_a.iter().zip(substs_b.iter()).all(|(arg_a, arg_b)| { - match (arg_a.unpack(), arg_b.unpack()) { - (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => { - inner_a == inner_b - } + substs_a + .iter() + .zip(substs_b.iter()) + .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) { + (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b, (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => { same_type_and_consts(type_a, type_b) - } + }, _ => true, - } - }) - } + }) + }, _ => a == b, } }