Revert "Auto merge of #92007 - oli-obk:lazy_tait2, r=nikomatsakis"
This reverts commite7cc3bddbe
, reversing changes made to734368a200
.
This commit is contained in:
parent
2d8b8f3593
commit
d54195db22
359 changed files with 2448 additions and 3311 deletions
|
@ -4,7 +4,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
|
|||
use rustc_hir::{self as hir, ExprKind};
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyS, TypeFoldable};
|
||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyS};
|
||||
use rustc_span::{MultiSpan, Span};
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{
|
||||
|
@ -98,7 +98,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
|
||||
all_arms_diverge &= self.diverges.get();
|
||||
|
||||
let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected);
|
||||
let opt_suggest_box_span =
|
||||
self.opt_suggest_box_span(arm.body.span, arm_ty, orig_expected);
|
||||
|
||||
let (arm_span, semi_span) =
|
||||
self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
|
||||
|
@ -503,15 +504,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// provide a structured suggestion in that case.
|
||||
pub(crate) fn opt_suggest_box_span(
|
||||
&self,
|
||||
span: Span,
|
||||
outer_ty: &'tcx TyS<'tcx>,
|
||||
orig_expected: Expectation<'tcx>,
|
||||
) -> Option<Span> {
|
||||
match orig_expected {
|
||||
Expectation::ExpectHasType(expected)
|
||||
if self.in_tail_expr
|
||||
&& self.ret_coercion.as_ref()?.borrow().merged_ty().has_opaque_types()
|
||||
&& self.can_coerce(outer_ty, expected) =>
|
||||
match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) {
|
||||
(Expectation::ExpectHasType(expected), Some((_id, ty)))
|
||||
if self.in_tail_expr && self.can_coerce(outer_ty, expected) =>
|
||||
{
|
||||
let impl_trait_ret_ty =
|
||||
self.infcx.instantiate_opaque_types(self.body_id, self.param_env, ty, span);
|
||||
assert!(
|
||||
impl_trait_ret_ty.obligations.is_empty(),
|
||||
"we should never get new obligations here"
|
||||
);
|
||||
let obligations = self.fulfillment_cx.borrow().pending_obligations();
|
||||
let mut suggest_box = !obligations.is_empty();
|
||||
for o in obligations {
|
||||
|
|
|
@ -545,7 +545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected: Expectation<'tcx>,
|
||||
fn_sig: ty::FnSig<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
// `fn_sig` is the *signature* of the closure being called. We
|
||||
// `fn_sig` is the *signature* of the cosure being called. We
|
||||
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
|
||||
// do know the types expected for each argument and the return
|
||||
// type.
|
||||
|
|
|
@ -17,7 +17,7 @@ use rustc_middle::ty::fold::TypeFoldable;
|
|||
use rustc_middle::ty::layout::MAX_SIMD_LANES;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
||||
use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, RegionKind, Ty, TyCtxt};
|
||||
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{self, MultiSpan, Span};
|
||||
|
@ -81,6 +81,8 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
can_be_generator: Option<hir::Movability>,
|
||||
return_type_pre_known: bool,
|
||||
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
|
||||
let mut fn_sig = fn_sig;
|
||||
|
||||
// Create the function context. This is either derived from scratch or,
|
||||
// in the case of closures, based on the outer context.
|
||||
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
|
||||
|
@ -93,8 +95,21 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
|
||||
let declared_ret_ty = fn_sig.output();
|
||||
|
||||
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(declared_ret_ty)));
|
||||
let revealed_ret_ty =
|
||||
fcx.instantiate_opaque_types_from_value(declared_ret_ty, decl.output.span());
|
||||
debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
|
||||
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
|
||||
fcx.ret_type_span = Some(decl.output.span());
|
||||
if let ty::Opaque(..) = declared_ret_ty.kind() {
|
||||
fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
|
||||
}
|
||||
fn_sig = tcx.mk_fn_sig(
|
||||
fn_sig.inputs().iter().cloned(),
|
||||
revealed_ret_ty,
|
||||
fn_sig.c_variadic,
|
||||
fn_sig.unsafety,
|
||||
fn_sig.abi,
|
||||
);
|
||||
|
||||
let span = body.value.span;
|
||||
|
||||
|
@ -236,7 +251,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
|
||||
debug!("actual_return_ty replaced with {:?}", actual_return_ty);
|
||||
}
|
||||
fcx.demand_suptype(span, declared_ret_ty, actual_return_ty);
|
||||
fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
|
||||
|
||||
// Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
|
||||
if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
|
||||
|
@ -614,8 +629,6 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
span: Span,
|
||||
origin: &hir::OpaqueTyOrigin,
|
||||
) {
|
||||
let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
|
||||
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let defining_use_anchor = match *origin {
|
||||
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
|
||||
|
@ -630,12 +643,24 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
|
||||
let misc_cause = traits::ObligationCause::misc(span, hir_id);
|
||||
|
||||
match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
|
||||
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
|
||||
Err(ty_err) => tcx.sess.delay_span_bug(
|
||||
span,
|
||||
&format!("could not unify `{}` with revealed type:\n{}", hidden_type, ty_err,),
|
||||
),
|
||||
let _ = inh.register_infer_ok_obligations(
|
||||
infcx.instantiate_opaque_types(hir_id, param_env, opaque_ty, span),
|
||||
);
|
||||
|
||||
let opaque_type_map = infcx.inner.borrow().opaque_types.clone();
|
||||
for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map {
|
||||
let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
|
||||
trace!(?hidden_type);
|
||||
match infcx.at(&misc_cause, param_env).eq(opaque_defn.concrete_ty, hidden_type) {
|
||||
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
|
||||
Err(ty_err) => tcx.sess.delay_span_bug(
|
||||
span,
|
||||
&format!(
|
||||
"could not check bounds on revealed type `{}`:\n{}",
|
||||
hidden_type, ty_err,
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
|
@ -647,7 +672,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
|
||||
match origin {
|
||||
// Checked when type checking the function containing them.
|
||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
|
||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
|
||||
// Can have different predicates to their defining use
|
||||
hir::OpaqueTyOrigin::TyAlias => {
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
|
@ -656,9 +681,6 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
fcx.regionck_item(hir_id, span, FxHashSet::default());
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up after ourselves
|
||||
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -3,20 +3,16 @@
|
|||
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
|
||||
|
||||
use crate::astconv::AstConv;
|
||||
use crate::rustc_middle::ty::subst::Subst;
|
||||
use hir::OpaqueTyOrigin;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
use rustc_infer::infer::{InferOk, InferResult};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
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 _;
|
||||
|
@ -176,29 +172,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected_ty: Ty<'tcx>,
|
||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||
match *expected_ty.kind() {
|
||||
ty::Opaque(def_id, substs) => {
|
||||
let bounds = self.tcx.explicit_item_bounds(def_id);
|
||||
let sig = bounds.iter().find_map(|(pred, span)| match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Projection(proj_predicate) => self
|
||||
.deduce_sig_from_projection(
|
||||
Some(*span),
|
||||
pred.kind().rebind(proj_predicate.subst(self.tcx, substs)),
|
||||
),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let kind = bounds
|
||||
.iter()
|
||||
.filter_map(|(pred, _)| match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Trait(tp) => {
|
||||
self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
|
||||
trace!(?sig, ?kind);
|
||||
(sig, kind)
|
||||
}
|
||||
ty::Dynamic(ref object_type, ..) => {
|
||||
let sig = object_type.projection_bounds().find_map(|pb| {
|
||||
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
|
||||
|
@ -224,7 +197,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||
let expected_sig =
|
||||
self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
|
||||
debug!(?obligation.predicate);
|
||||
debug!(
|
||||
"deduce_expectations_from_obligations: obligation.predicate={:?}",
|
||||
obligation.predicate
|
||||
);
|
||||
|
||||
let bound_predicate = obligation.predicate.kind();
|
||||
if let ty::PredicateKind::Projection(proj_predicate) =
|
||||
|
@ -425,14 +401,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,
|
||||
|
@ -619,8 +590,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
_ => 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(
|
||||
|
@ -641,57 +610,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
result
|
||||
}
|
||||
|
||||
fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> {
|
||||
ty.fold_with(&mut ty::fold::BottomUpFolder {
|
||||
tcx: self.infcx.tcx,
|
||||
lt_op: |lt| lt,
|
||||
ct_op: |ct| ct,
|
||||
ty_op: |ty| match *ty.kind() {
|
||||
// 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.
|
||||
ty::Opaque(def_id, _substs)
|
||||
if matches!(
|
||||
self.infcx.opaque_type_origin(def_id, DUMMY_SP),
|
||||
Some(OpaqueTyOrigin::FnReturn(..))
|
||||
) =>
|
||||
{
|
||||
let ty_var = self.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeInference,
|
||||
span,
|
||||
});
|
||||
let cause = ObligationCause::misc(span, body_id);
|
||||
self.register_predicates(vec![self.infcx.opaque_ty_obligation(
|
||||
ty,
|
||||
ty_var,
|
||||
true,
|
||||
self.param_env,
|
||||
cause,
|
||||
)]);
|
||||
ty_var
|
||||
}
|
||||
_ => ty,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// 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>> {
|
||||
debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id);
|
||||
|
||||
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")
|
||||
});
|
||||
|
||||
// In practice, the return type of the surrounding function is
|
||||
// always a (not yet resolved) inference variable, because it
|
||||
// is the hidden type for an `impl Trait` that we are going to
|
||||
// be inferring.
|
||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
|
||||
let (def_id, substs) = match *ret_ty.kind() {
|
||||
ty::Opaque(def_id, substs) => (def_id, substs),
|
||||
let ret_vid = match *ret_ty.kind() {
|
||||
ty::Infer(ty::TyVar(ret_vid)) => ret_vid,
|
||||
ty::Error(_) => return None,
|
||||
_ => span_bug!(
|
||||
self.tcx.def_span(expr_def_id),
|
||||
|
@ -699,19 +638,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
),
|
||||
};
|
||||
|
||||
let item_bounds = self.tcx.explicit_item_bounds(def_id);
|
||||
|
||||
// Search for a pending obligation like
|
||||
//
|
||||
// `<R as Future>::Output = T`
|
||||
//
|
||||
// where R is the return type we are expecting. This type `T`
|
||||
// will be our output.
|
||||
let output_ty = item_bounds.iter().find_map(|&(predicate, span)| {
|
||||
let bound_predicate = predicate.subst(self.tcx, substs).kind();
|
||||
let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
|
||||
let bound_predicate = obligation.predicate.kind();
|
||||
if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
|
||||
self.deduce_future_output_from_projection(
|
||||
span,
|
||||
obligation.cause.span,
|
||||
bound_predicate.rebind(proj_predicate),
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -1275,7 +1275,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
|
||||
/// Returns the current "merged type", representing our best-guess
|
||||
/// at the LUB of the expressions we've seen so far (if any). This
|
||||
/// isn't *final* until you call `self.complete()`, which will return
|
||||
/// isn't *final* until you call `self.final()`, which will return
|
||||
/// the merged type.
|
||||
pub fn merged_ty(&self) -> Ty<'tcx> {
|
||||
self.final_ty.unwrap_or(self.expected_ty)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::{self, Span};
|
||||
|
||||
use super::Expectation::*;
|
||||
|
@ -44,7 +43,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
|
|||
// when checking the 'then' block which are incompatible with the
|
||||
// 'else' branch.
|
||||
pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
|
||||
match self.strip_opaque(fcx) {
|
||||
match *self {
|
||||
ExpectHasType(ety) => {
|
||||
let ety = fcx.shallow_resolve(ety);
|
||||
if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
|
||||
|
@ -105,35 +104,14 @@ impl<'a, 'tcx> Expectation<'tcx> {
|
|||
/// for the program to type-check). `only_has_type` will return
|
||||
/// such a constraint, if it exists.
|
||||
pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
|
||||
match self.strip_opaque(fcx) {
|
||||
ExpectHasType(ty) => Some(ty),
|
||||
match self {
|
||||
ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)),
|
||||
NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// We must not treat opaque types as expected types in their defining scope, as that
|
||||
/// will break `fn foo() -> impl Trait { if cond { a } else { b } }` if `a` and `b` are
|
||||
/// only "equal" if they coerce to a common target, like two different function items
|
||||
/// coercing to a function pointer if they have the same signature.
|
||||
fn strip_opaque(self, fcx: &FnCtxt<'a, 'tcx>) -> Self {
|
||||
match self {
|
||||
ExpectHasType(ty) => {
|
||||
let ty = fcx.resolve_vars_if_possible(ty);
|
||||
match *ty.kind() {
|
||||
ty::Opaque(def_id, _)
|
||||
if fcx.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() =>
|
||||
{
|
||||
NoExpectation
|
||||
}
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `only_has_type`, but instead of returning `None` if no
|
||||
/// hard constraint exists, creates a fresh type variable.
|
||||
pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> {
|
||||
|
|
|
@ -956,7 +956,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
let else_diverges = self.diverges.get();
|
||||
|
||||
let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected);
|
||||
let opt_suggest_box_span =
|
||||
self.opt_suggest_box_span(else_expr.span, else_ty, orig_expected);
|
||||
let if_cause =
|
||||
self.if_cause(sp, then_expr, else_expr, then_ty, else_ty, opt_suggest_box_span);
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
self.fulfillment_cx.borrow_mut().pending_obligations()
|
||||
);
|
||||
|
||||
// Check if we have any unsolved variables. If not, no need for fallback.
|
||||
// Check if we have any unsolved varibales. If not, no need for fallback.
|
||||
let unsolved_variables = self.unsolved_variables();
|
||||
if unsolved_variables.is_empty() {
|
||||
return false;
|
||||
|
@ -66,6 +66,16 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
// refer to opaque types.
|
||||
self.select_obligations_where_possible(fallback_has_occurred, |_| {});
|
||||
|
||||
// We now run fallback again, but this time we allow it to replace
|
||||
// unconstrained opaque type variables, in addition to performing
|
||||
// other kinds of fallback.
|
||||
for ty in &self.unsolved_variables() {
|
||||
fallback_has_occurred |= self.fallback_opaque_type_vars(ty);
|
||||
}
|
||||
|
||||
// See if we can make any more progress.
|
||||
self.select_obligations_where_possible(fallback_has_occurred, |_| {});
|
||||
|
||||
fallback_has_occurred
|
||||
}
|
||||
|
||||
|
@ -126,6 +136,59 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
true
|
||||
}
|
||||
|
||||
/// Second round of fallback: Unconstrained type variables created
|
||||
/// from the instantiation of an opaque type fall back to the
|
||||
/// opaque type itself. This is a somewhat incomplete attempt to
|
||||
/// manage "identity passthrough" for `impl Trait` types.
|
||||
///
|
||||
/// For example, in this code:
|
||||
///
|
||||
///```
|
||||
/// type MyType = impl Copy;
|
||||
/// fn defining_use() -> MyType { true }
|
||||
/// fn other_use() -> MyType { defining_use() }
|
||||
/// ```
|
||||
///
|
||||
/// `defining_use` will constrain the instantiated inference
|
||||
/// variable to `bool`, while `other_use` will constrain
|
||||
/// the instantiated inference variable to `MyType`.
|
||||
///
|
||||
/// When we process opaque types during writeback, we
|
||||
/// will handle cases like `other_use`, and not count
|
||||
/// them as defining usages
|
||||
///
|
||||
/// However, we also need to handle cases like this:
|
||||
///
|
||||
/// ```rust
|
||||
/// pub type Foo = impl Copy;
|
||||
/// fn produce() -> Option<Foo> {
|
||||
/// None
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// In the above snippet, the inference variable created by
|
||||
/// instantiating `Option<Foo>` will be completely unconstrained.
|
||||
/// We treat this as a non-defining use by making the inference
|
||||
/// variable fall back to the opaque type itself.
|
||||
fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool {
|
||||
let span = self
|
||||
.infcx
|
||||
.type_var_origin(ty)
|
||||
.map(|origin| origin.span)
|
||||
.unwrap_or(rustc_span::DUMMY_SP);
|
||||
let oty = self.inner.borrow().opaque_types_vars.get(ty).copied();
|
||||
if let Some(opaque_ty) = oty {
|
||||
debug!(
|
||||
"fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
|
||||
ty, opaque_ty
|
||||
);
|
||||
self.demand_eqtype(span, ty, opaque_ty);
|
||||
true
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// The "diverging fallback" system is rather complicated. This is
|
||||
/// a result of our need to balance 'do the right thing' with
|
||||
/// backwards compatibility.
|
||||
|
|
|
@ -367,6 +367,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
(result, spans)
|
||||
}
|
||||
|
||||
/// Replaces the opaque types from the given value with type variables,
|
||||
/// and records the `OpaqueTypeMap` for later use during writeback. See
|
||||
/// `InferCtxt::instantiate_opaque_types` for more details.
|
||||
#[instrument(skip(self, value_span), level = "debug")]
|
||||
pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
|
||||
&self,
|
||||
value: T,
|
||||
value_span: Span,
|
||||
) -> T {
|
||||
self.register_infer_ok_obligations(self.instantiate_opaque_types(
|
||||
self.body_id,
|
||||
self.param_env,
|
||||
value,
|
||||
value_span,
|
||||
))
|
||||
}
|
||||
|
||||
/// Convenience method which tracks extra diagnostic information for normalization
|
||||
/// that occurs as a result of WF checking. The `hir_id` is the `HirId` of the hir item
|
||||
/// whose type is being wf-checked - this is used to construct a more precise span if
|
||||
|
@ -703,7 +720,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// inference variable.
|
||||
ty::PredicateKind::ClosureKind(..) => None,
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
ty::PredicateKind::OpaqueType(..) => None,
|
||||
}
|
||||
})
|
||||
.filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
|
||||
|
|
|
@ -57,6 +57,8 @@ pub struct FnCtxt<'a, 'tcx> {
|
|||
/// any).
|
||||
pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
|
||||
|
||||
pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>,
|
||||
|
||||
pub(super) ret_type_span: Option<Span>,
|
||||
|
||||
/// Used exclusively to reduce cost of advanced evaluation used for
|
||||
|
@ -128,6 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
param_env,
|
||||
err_count_on_creation: inh.tcx.sess.err_count(),
|
||||
ret_coercion: None,
|
||||
ret_coercion_impl_trait: None,
|
||||
ret_type_span: None,
|
||||
in_tail_expr: false,
|
||||
ret_coercion_span: Cell::new(None),
|
||||
|
|
|
@ -95,13 +95,6 @@ impl<'tcx> InheritedBuilder<'tcx> {
|
|||
let def_id = self.def_id;
|
||||
self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
|
||||
}
|
||||
|
||||
/// WF-checking doesn't need to recompute opaque types and can instead use
|
||||
/// the type_of query to get them from typeck.
|
||||
pub fn reveal_defining_opaque_types(mut self) -> Self {
|
||||
self.infcx = self.infcx.reveal_defining_opaque_types();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
||||
|
@ -126,8 +119,8 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
|
||||
debug!("register_predicate({:?})", obligation);
|
||||
if obligation.has_escaping_bound_vars() {
|
||||
span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
|
||||
}
|
||||
|
|
|
@ -856,7 +856,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
| ty::PredicateKind::TypeOutlives(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
});
|
||||
|
@ -1476,7 +1475,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
TraitCandidate(trait_ref) => self.probe(|_| {
|
||||
let _ = self
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.define_opaque_types(false)
|
||||
.sup(candidate.xform_self_ty, self_ty);
|
||||
match self.select_trait_candidate(trait_ref) {
|
||||
Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
|
||||
|
@ -1506,7 +1504,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
// First check that the self type can be related.
|
||||
let sub_obligations = match self
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.define_opaque_types(false)
|
||||
.sup(probe.xform_self_ty, self_ty)
|
||||
{
|
||||
Ok(InferOk { obligations, value: () }) => obligations,
|
||||
|
@ -1654,7 +1651,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
);
|
||||
if self
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.define_opaque_types(false)
|
||||
.sup(return_ty, xform_ret_ty)
|
||||
.is_err()
|
||||
{
|
||||
|
|
|
@ -341,7 +341,6 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T
|
|||
typeck_with_fallback(tcx, def_id, fallback)
|
||||
}
|
||||
|
||||
#[instrument(skip(tcx, fallback))]
|
||||
fn typeck_with_fallback<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
|
|
|
@ -335,6 +335,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Returns a list of `Ty`s for each upvar.
|
||||
fn final_upvar_tys(&self, closure_id: DefId) -> Vec<Ty<'tcx>> {
|
||||
// Presently an unboxed closure type cannot "escape" out of a
|
||||
// function, so we will only encounter ones that originated in the
|
||||
// local crate or were inlined into it along with some function.
|
||||
// This may change if abstract return types of some sort are
|
||||
// implemented.
|
||||
self.typeck_results
|
||||
.borrow()
|
||||
.closure_min_captures_flattened(closure_id)
|
||||
|
|
|
@ -895,7 +895,7 @@ fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<
|
|||
|
||||
fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> {
|
||||
CheckWfFcxBuilder {
|
||||
inherited: Inherited::build(tcx, def_id).reveal_defining_opaque_types(),
|
||||
inherited: Inherited::build(tcx, def_id),
|
||||
id: hir::HirId::make_owner(def_id),
|
||||
span,
|
||||
param_env: tcx.param_env(def_id),
|
||||
|
|
|
@ -18,6 +18,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
|||
use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::opaque_types::InferCtxtExt;
|
||||
|
||||
use std::mem;
|
||||
|
||||
|
@ -64,7 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
wbcx.visit_closures();
|
||||
wbcx.visit_liberated_fn_sigs();
|
||||
wbcx.visit_fru_field_types();
|
||||
wbcx.visit_opaque_types();
|
||||
wbcx.visit_opaque_types(body.value.span);
|
||||
wbcx.visit_coercion_casts();
|
||||
wbcx.visit_user_provided_tys();
|
||||
wbcx.visit_user_provided_sigs();
|
||||
|
@ -495,18 +496,64 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
fcx_typeck_results.generator_interior_types.clone();
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn visit_opaque_types(&mut self) {
|
||||
let opaque_types =
|
||||
self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
for (opaque_type_key, decl) in opaque_types {
|
||||
let hidden_type = match decl.origin {
|
||||
hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => {
|
||||
Some(self.resolve(decl.hidden_type.ty, &decl.hidden_type.span))
|
||||
#[instrument(skip(self, span), level = "debug")]
|
||||
fn visit_opaque_types(&mut self, span: Span) {
|
||||
let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone();
|
||||
for (opaque_type_key, opaque_defn) in opaque_types {
|
||||
let hir_id =
|
||||
self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local());
|
||||
let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id);
|
||||
|
||||
debug_assert!(!instantiated_ty.has_escaping_bound_vars());
|
||||
|
||||
let opaque_type_key = self.fcx.fully_resolve(opaque_type_key).unwrap();
|
||||
|
||||
// Prevent:
|
||||
// * `fn foo<T>() -> Foo<T>`
|
||||
// * `fn foo<T: Bound + Other>() -> Foo<T>`
|
||||
// from being defining.
|
||||
|
||||
// Also replace all generic params with the ones from the opaque type
|
||||
// definition so that
|
||||
// ```rust
|
||||
// type Foo<T> = impl Baz + 'static;
|
||||
// fn foo<U>() -> Foo<U> { .. }
|
||||
// ```
|
||||
// figures out the concrete type with `U`, but the stored type is with `T`.
|
||||
|
||||
// FIXME: why are we calling this here? This seems too early, and duplicated.
|
||||
let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
|
||||
opaque_type_key,
|
||||
instantiated_ty,
|
||||
span,
|
||||
);
|
||||
|
||||
let mut skip_add = false;
|
||||
|
||||
if let ty::Opaque(definition_ty_def_id, _substs) = *definition_ty.kind() {
|
||||
if opaque_defn.origin == hir::OpaqueTyOrigin::TyAlias {
|
||||
if opaque_type_key.def_id == definition_ty_def_id {
|
||||
debug!(
|
||||
"skipping adding concrete definition for opaque type {:?} {:?}",
|
||||
opaque_defn, opaque_type_key.def_id
|
||||
);
|
||||
skip_add = true;
|
||||
}
|
||||
}
|
||||
hir::OpaqueTyOrigin::TyAlias => None,
|
||||
};
|
||||
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
|
||||
}
|
||||
|
||||
if opaque_type_key.substs.needs_infer() {
|
||||
span_bug!(span, "{:#?} has inference variables", opaque_type_key.substs)
|
||||
}
|
||||
|
||||
// We only want to add an entry into `concrete_opaque_types`
|
||||
// if we actually found a defining usage of this opaque type.
|
||||
// Otherwise, we do nothing - we'll either find a defining usage
|
||||
// in some other location, or we'll end up emitting an error due
|
||||
// to the lack of defining usage
|
||||
if !skip_add {
|
||||
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -389,22 +389,28 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
.get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
|
||||
.copied()
|
||||
.unwrap_or_else(|| {
|
||||
let table = tcx.typeck(owner);
|
||||
if let Some(ErrorReported) = table.tainted_by_errors {
|
||||
tcx.sess.delay_span_bug(
|
||||
DUMMY_SP,
|
||||
&format!(
|
||||
"owner {:?} has no opaque type for {:?} in its typeck results",
|
||||
owner, def_id,
|
||||
),
|
||||
);
|
||||
if let Some(ErrorReported) =
|
||||
tcx.typeck(owner).tainted_by_errors
|
||||
{
|
||||
// Some error in the
|
||||
// owner fn prevented us from populating
|
||||
// the `concrete_opaque_types` table.
|
||||
tcx.ty_error()
|
||||
} else {
|
||||
table.concrete_opaque_types.get(&def_id.to_def_id()).copied().unwrap_or_else(|| {
|
||||
// We failed to resolve the opaque type or it
|
||||
// resolves to itself. We interpret this as the
|
||||
// no values of the hidden type ever being constructed,
|
||||
// so we can just make the hidden type be `!`.
|
||||
// For backwards compatibility reasons, we fall back to
|
||||
// `()` until we the diverging default is changed.
|
||||
Some(tcx.mk_diverging_default())
|
||||
}).expect("RPIT always have a hidden type from typeck")
|
||||
// We failed to resolve the opaque type or it
|
||||
// resolves to itself. Return the non-revealed
|
||||
// type, which should result in E0720.
|
||||
tcx.mk_opaque(
|
||||
def_id.to_def_id(),
|
||||
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
|
||||
)
|
||||
}
|
||||
});
|
||||
debug!("concrete_ty = {:?}", concrete_ty);
|
||||
|
@ -598,21 +604,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
}
|
||||
// Calling `mir_borrowck` can lead to cycle errors through
|
||||
// const-checking, avoid calling it if we don't have to.
|
||||
// ```rust
|
||||
// type Foo = impl Fn() -> usize; // when computing type for this
|
||||
// const fn bar() -> Foo {
|
||||
// || 0usize
|
||||
// }
|
||||
// const BAZR: Foo = bar(); // we would mir-borrowck this, causing cycles
|
||||
// // because we again need to reveal `Foo` so we can check whether the
|
||||
// // constant does not contain interior mutability.
|
||||
// ```
|
||||
let tables = self.tcx.typeck(def_id);
|
||||
if let Some(_) = tables.tainted_by_errors {
|
||||
self.found = Some((DUMMY_SP, self.tcx.ty_error()));
|
||||
return;
|
||||
}
|
||||
if tables.concrete_opaque_types.get(&self.def_id).is_none() {
|
||||
if !self.tcx.typeck(def_id).concrete_opaque_types.contains(&self.def_id) {
|
||||
debug!("no constraints in typeck results");
|
||||
return;
|
||||
}
|
||||
|
@ -666,7 +658,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
intravisit::walk_expr(self, ex);
|
||||
}
|
||||
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
|
||||
trace!(?it.def_id);
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
// The opaque type itself or its children are not within its reveal scope.
|
||||
if it.def_id.to_def_id() != self.def_id {
|
||||
self.check(it.def_id);
|
||||
|
@ -674,7 +666,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
}
|
||||
}
|
||||
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
|
||||
trace!(?it.def_id);
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
// The opaque type itself or its children are not within its reveal scope.
|
||||
if it.def_id.to_def_id() != self.def_id {
|
||||
self.check(it.def_id);
|
||||
|
@ -682,7 +674,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
}
|
||||
}
|
||||
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
|
||||
trace!(?it.def_id);
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
self.check(it.def_id);
|
||||
intravisit::walk_trait_item(self, it);
|
||||
}
|
||||
|
@ -692,12 +684,12 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
let scope = tcx.hir().get_defining_scope(hir_id);
|
||||
let mut locator = ConstraintLocator { def_id: def_id.to_def_id(), tcx, found: None };
|
||||
|
||||
debug!(?scope);
|
||||
debug!("find_opaque_ty_constraints: scope={:?}", scope);
|
||||
|
||||
if scope == hir::CRATE_HIR_ID {
|
||||
tcx.hir().walk_toplevel_module(&mut locator);
|
||||
} else {
|
||||
trace!("scope={:#?}", tcx.hir().get(scope));
|
||||
debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
|
||||
match tcx.hir().get(scope) {
|
||||
// We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
|
||||
// This allows our visitor to process the defining item itself, causing
|
||||
|
@ -724,12 +716,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
Some((_, ty)) => ty,
|
||||
None => {
|
||||
let span = tcx.def_span(def_id);
|
||||
let name = tcx.item_name(tcx.parent(def_id.to_def_id()).unwrap());
|
||||
let label = format!(
|
||||
"`{}` must be used in combination with a concrete type within the same module",
|
||||
name
|
||||
);
|
||||
tcx.sess.struct_span_err(span, "unconstrained opaque type").note(&label).emit();
|
||||
tcx.sess.span_err(span, "could not find defining uses");
|
||||
tcx.ty_error()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -427,7 +427,6 @@ fn trait_predicate_kind<'tcx>(
|
|||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,6 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
|||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue