Skip to content

Make TAIT behave exactly like RPIT #96727

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

Merged
merged 3 commits into from
Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
The only reason we had to replace opaque types in closures was due to…
… async fn desugaring, make that explicit
  • Loading branch information
oli-obk committed Jun 29, 2022
commit c33b127d7c25977817faaae5eee84d57cde37c68
26 changes: 4 additions & 22 deletions compiler/rustc_infer/src/infer/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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,
Expand All @@ -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.
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
73 changes: 31 additions & 42 deletions compiler/rustc_typeck/src/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 _;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand All @@ -646,31 +637,18 @@ 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
/// user specified. The "desugared" return type is an `impl
/// Future<Output = T>`, 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<Ty<'tcx>> {
fn deduce_future_output_from_obligations(
&self,
expr_def_id: DefId,
body_id: hir::HirId,
) -> Option<Ty<'tcx>> {
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")
});
Expand Down Expand Up @@ -700,23 +678,34 @@ 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),
"async fn generator return type not an inference variable"
),
};

// 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
Expand Down