From c33b127d7c25977817faaae5eee84d57cde37c68 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Jun 2022 08:52:19 +0000 Subject: [PATCH] The only reason we had to replace opaque types in closures was due to async fn desugaring, make that explicit --- .../rustc_infer/src/infer/opaque_types.rs | 26 +------ compiler/rustc_typeck/src/check/check.rs | 3 - compiler/rustc_typeck/src/check/closure.rs | 73 ++++++++----------- 3 files changed, 35 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 7d7fa9f2941..cc36d6a0a4f 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -5,7 +5,7 @@ use hir::{HirId, OpaqueTyOrigin}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; -use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::subst::{GenericArgKind, Subst}; use rustc_middle::ty::{ @@ -38,38 +38,19 @@ pub struct OpaqueTypeDecl<'tcx> { pub origin: hir::OpaqueTyOrigin, } -pub enum ReplaceOpaqueTypes { - /// Closures can't create hidden types for opaque types of their parent, as they - /// do not have all the outlives information available. Also `type_of` looks for - /// hidden types in the owner (so the closure's parent), so it would not find these - /// definitions. - OnlyForRPIT, - All, -} - impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn replace_opaque_types_with_inference_vars( &self, ty: Ty<'tcx>, body_id: HirId, span: Span, - code: ObligationCauseCode<'tcx>, param_env: ty::ParamEnv<'tcx>, - replace: ReplaceOpaqueTypes, ) -> InferOk<'tcx, Ty<'tcx>> { if !ty.has_opaque_types() { return InferOk { value: ty, obligations: vec![] }; } let mut obligations = vec![]; - let replace_opaque_type = |def_id| match self.opaque_type_origin(def_id, span) { - None => false, - Some(OpaqueTyOrigin::FnReturn(..)) => true, - // Not using `==` or `matches!` here to make sure we exhaustively match variants. - Some(_) => match replace { - ReplaceOpaqueTypes::OnlyForRPIT => false, - ReplaceOpaqueTypes::All => true, - }, - }; + let replace_opaque_type = |def_id| self.opaque_type_origin(def_id, span).is_some(); let value = ty.fold_with(&mut ty::fold::BottomUpFolder { tcx: self.tcx, lt_op: |lt| lt, @@ -78,7 +59,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::Opaque(def_id, _substs) if replace_opaque_type(def_id) => { let def_span = self.tcx.def_span(def_id); let span = if span.contains(def_span) { def_span } else { span }; - let cause = ObligationCause::new(span, body_id, code.clone()); + let code = traits::ObligationCauseCode::OpaqueReturnType(None); + let cause = ObligationCause::new(span, body_id, code); // FIXME(compiler-errors): We probably should add a new TypeVariableOriginKind // for opaque types, and then use that kind to fix the spans for type errors // that we see later on. diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 184bc4188c5..1cd66d1426d 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -13,7 +13,6 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ItemKind, Node, PathSegment}; -use rustc_infer::infer::opaque_types::ReplaceOpaqueTypes; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; @@ -97,9 +96,7 @@ pub(super) fn check_fn<'a, 'tcx>( declared_ret_ty, body.value.hir_id, decl.output.span(), - traits::ObligationCauseCode::OpaqueReturnType(None), param_env, - ReplaceOpaqueTypes::All, )); // If we replaced declared_ret_ty with infer vars, then we must be infering // an opaque type, so set a flag so we can improve diagnostics. diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 918a42cf02b..131e594ed94 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -7,16 +7,13 @@ use crate::rustc_middle::ty::subst::Subst; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::opaque_types::ReplaceOpaqueTypes; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::infer::{InferOk, InferResult}; -use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Span; -use rustc_span::DUMMY_SP; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::ArgKind; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; @@ -430,14 +427,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in this binder we are creating. assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST)); let bound_sig = expected_sig.sig.map_bound(|sig| { - let output = self.hide_parent_opaque_types( - sig.output(), - expected_sig.cause_span.unwrap_or(DUMMY_SP), - body.id().hir_id, - ); self.tcx.mk_fn_sig( sig.inputs().iter().cloned(), - output, + sig.output(), sig.c_variadic, hir::Unsafety::Normal, Abi::RustCall, @@ -609,23 +601,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // function. Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => { debug!("closure is async fn body"); - self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| { - // AFAIK, deducing the future output - // always succeeds *except* in error cases - // like #65159. I'd like to return Error - // here, but I can't because I can't - // easily (and locally) prove that we - // *have* reported an - // error. --nikomatsakis - astconv.ty_infer(None, decl.output.span()) - }) + self.deduce_future_output_from_obligations(expr_def_id, body.id().hir_id) + .unwrap_or_else(|| { + // AFAIK, deducing the future output + // always succeeds *except* in error cases + // like #65159. I'd like to return Error + // here, but I can't because I can't + // easily (and locally) prove that we + // *have* reported an + // error. --nikomatsakis + astconv.ty_infer(None, decl.output.span()) + }) } _ => astconv.ty_infer(None, decl.output.span()), }, }; - let supplied_return = - self.hide_parent_opaque_types(supplied_return, decl.output.span(), body.id().hir_id); let result = ty::Binder::bind_with_vars( self.tcx.mk_fn_sig( @@ -646,23 +637,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { result } - /// Closures can't create hidden types for opaque types of their parent, as they - /// do not have all the outlives information available. Also `type_of` looks for - /// hidden types in the owner (so the closure's parent), so it would not find these - /// definitions. - fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> { - let InferOk { value, obligations } = self.replace_opaque_types_with_inference_vars( - ty, - body_id, - span, - ObligationCauseCode::MiscObligation, - self.param_env, - ReplaceOpaqueTypes::OnlyForRPIT, - ); - self.register_predicates(obligations); - value - } - /// Invoked when we are translating the generator that results /// from desugaring an `async fn`. Returns the "sugared" return /// type of the `async fn` -- that is, the return type that the @@ -670,7 +644,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Future`, so we do this by searching through the /// obligations to extract the `T`. #[instrument(skip(self), level = "debug")] - fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option> { + fn deduce_future_output_from_obligations( + &self, + expr_def_id: DefId, + body_id: hir::HirId, + ) -> Option> { let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| { span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn") }); @@ -700,14 +678,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Infer(ty::TyVar(ret_vid)) => { self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| { get_future_output(obligation.predicate, obligation.cause.span) - }) + })? } ty::Opaque(def_id, substs) => self .tcx .bound_explicit_item_bounds(def_id) .transpose_iter() .map(|e| e.map_bound(|e| *e).transpose_tuple2()) - .find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0)), + .find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0))?, ty::Error(_) => return None, _ => span_bug!( self.tcx.def_span(expr_def_id), @@ -715,8 +693,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), }; + // async fn that have opaque types in their return type need to redo the conversion to inference variables + // as they fetch the still opaque version from the signature. + let InferOk { value: output_ty, obligations } = self + .replace_opaque_types_with_inference_vars( + output_ty, + body_id, + self.tcx.def_span(expr_def_id), + self.param_env, + ); + self.register_predicates(obligations); + debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty); - output_ty + Some(output_ty) } /// Given a projection like