Auto merge of #94081 - oli-obk:lazy_tait_take_two, r=nikomatsakis
Lazy type-alias-impl-trait take two ### user visible change 1: RPIT inference from recursive call sites Lazy TAIT has an insta-stable change. The following snippet now compiles, because opaque types can now have their hidden type set from wherever the opaque type is mentioned. ```rust fn bar(b: bool) -> impl std::fmt::Debug { if b { return 42 } let x: u32 = bar(false); // this errors on stable 99 } ``` The return type of `bar` stays opaque, you can't do `bar(false) + 42`, you need to actually mention the hidden type. ### user visible change 2: divergence between RPIT and TAIT in return statements Note that `return` statements and the trailing return expression are special with RPIT (but not TAIT). So ```rust #![feature(type_alias_impl_trait)] type Foo = impl std::fmt::Debug; fn foo(b: bool) -> Foo { if b { return vec![42]; } std::iter::empty().collect() //~ ERROR `Foo` cannot be built from an iterator } fn bar(b: bool) -> impl std::fmt::Debug { if b { return vec![42] } std::iter::empty().collect() // Works, magic (accidentally stabilized, not intended) } ``` But when we are working with the return value of a recursive call, the behavior of RPIT and TAIT is the same: ```rust type Foo = impl std::fmt::Debug; fn foo(b: bool) -> Foo { if b { return vec![]; } let mut x = foo(false); x = std::iter::empty().collect(); //~ ERROR `Foo` cannot be built from an iterator vec![] } fn bar(b: bool) -> impl std::fmt::Debug { if b { return vec![]; } let mut x = bar(false); x = std::iter::empty().collect(); //~ ERROR `impl Debug` cannot be built from an iterator vec![] } ``` ### user visible change 3: TAIT does not merge types across branches In contrast to RPIT, TAIT does not merge types across branches, so the following does not compile. ```rust type Foo = impl std::fmt::Debug; fn foo(b: bool) -> Foo { if b { vec![42_i32] } else { std::iter::empty().collect() //~^ ERROR `Foo` cannot be built from an iterator over elements of type `_` } } ``` It is easy to support, but we should make an explicit decision to include the additional complexity in the implementation (it's not much, see a721052457cf513487fb4266e3ade65c29b272d2 which needs to be reverted to enable this). ### PR formalities previous attempt: #92007 This PR also includes #92306 and #93783, as they were reverted along with #92007 in #93893 fixes #93411 fixes #88236 fixes #89312 fixes #87340 fixes #86800 fixes #86719 fixes #84073 fixes #83919 fixes #82139 fixes #77987 fixes #74282 fixes #67830 fixes #62742 fixes #54895
This commit is contained in:
commit
f132bcf3bd
419 changed files with 5208 additions and 2490 deletions
|
@ -4,7 +4,7 @@ use rustc_errors::{Applicability, Diagnostic};
|
|||
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};
|
||||
use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
|
||||
use rustc_span::{MultiSpan, Span};
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{
|
||||
|
@ -98,8 +98,7 @@ 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.body.span, arm_ty, orig_expected);
|
||||
let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected);
|
||||
|
||||
let (arm_span, semi_span) =
|
||||
self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
|
||||
|
@ -504,20 +503,15 @@ 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: Ty<'tcx>,
|
||||
orig_expected: Expectation<'tcx>,
|
||||
) -> Option<Span> {
|
||||
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) =>
|
||||
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) =>
|
||||
{
|
||||
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 {
|
||||
|
|
|
@ -538,7 +538,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected: Expectation<'tcx>,
|
||||
fn_sig: ty::FnSig<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
// `fn_sig` is the *signature* of the cosure being called. We
|
||||
// `fn_sig` is the *signature* of the closure 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::{LayoutError, MAX_SIMD_LANES};
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{self, MultiSpan, Span};
|
||||
|
@ -83,8 +83,6 @@ 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);
|
||||
|
@ -97,21 +95,15 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
|
||||
let declared_ret_ty = fn_sig.output();
|
||||
|
||||
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)));
|
||||
let ret_ty =
|
||||
fcx.register_infer_ok_obligations(fcx.infcx.replace_opaque_types_with_inference_vars(
|
||||
declared_ret_ty,
|
||||
body.value.hir_id,
|
||||
DUMMY_SP,
|
||||
param_env,
|
||||
));
|
||||
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(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;
|
||||
|
||||
|
@ -253,7 +245,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, revealed_ret_ty, actual_return_ty);
|
||||
fcx.demand_suptype(span, declared_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() {
|
||||
|
@ -656,6 +648,8 @@ 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,
|
||||
|
@ -670,25 +664,13 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
|
||||
let misc_cause = traits::ObligationCause::misc(span, hir_id);
|
||||
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
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,),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -701,7 +683,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
|
||||
match origin {
|
||||
// Checked when type checking the function containing them.
|
||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
|
||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
|
||||
// Can have different predicates to their defining use
|
||||
hir::OpaqueTyOrigin::TyAlias => {
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
|
@ -710,6 +692,9 @@ 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,6 +3,7 @@
|
|||
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
|
||||
|
||||
use crate::astconv::AstConv;
|
||||
use crate::rustc_middle::ty::subst::Subst;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
|
@ -13,6 +14,7 @@ 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 _;
|
||||
|
@ -172,6 +174,29 @@ 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);
|
||||
|
@ -197,10 +222,7 @@ 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!(
|
||||
"deduce_expectations_from_obligations: obligation.predicate={:?}",
|
||||
obligation.predicate
|
||||
);
|
||||
debug!(?obligation.predicate);
|
||||
|
||||
let bound_predicate = obligation.predicate.kind();
|
||||
if let ty::PredicateKind::Projection(proj_predicate) =
|
||||
|
@ -235,6 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// The `cause_span` should be the span that caused us to
|
||||
/// have this expected signature, or `None` if we can't readily
|
||||
/// know that.
|
||||
#[instrument(level = "debug", skip(self, cause_span))]
|
||||
fn deduce_sig_from_projection(
|
||||
&self,
|
||||
cause_span: Option<Span>,
|
||||
|
@ -242,15 +265,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) -> Option<ExpectedSig<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
debug!("deduce_sig_from_projection({:?})", projection);
|
||||
|
||||
let trait_def_id = projection.trait_def_id(tcx);
|
||||
|
||||
let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
|
||||
let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
|
||||
let is_gen = gen_trait == trait_def_id;
|
||||
if !is_fn && !is_gen {
|
||||
debug!("deduce_sig_from_projection: not fn or generator");
|
||||
debug!("not fn or generator");
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -259,7 +280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// associated item and not yield.
|
||||
let return_assoc_item = self.tcx.associated_item_def_ids(gen_trait)[1];
|
||||
if return_assoc_item != projection.projection_def_id() {
|
||||
debug!("deduce_sig_from_projection: not return assoc item of generator");
|
||||
debug!("not return assoc item of generator");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let input_tys = if is_fn {
|
||||
let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
|
||||
let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
|
||||
debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
|
||||
debug!(?arg_param_ty);
|
||||
|
||||
match arg_param_ty.kind() {
|
||||
&ty::Tuple(tys) => tys,
|
||||
|
@ -282,7 +303,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Since this is a return parameter type it is safe to unwrap.
|
||||
let ret_param_ty = projection.skip_binder().term.ty().unwrap();
|
||||
let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
|
||||
debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
|
||||
debug!(?ret_param_ty);
|
||||
|
||||
let sig = projection.rebind(self.tcx.mk_fn_sig(
|
||||
input_tys.iter(),
|
||||
|
@ -291,7 +312,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
hir::Unsafety::Normal,
|
||||
Abi::Rust,
|
||||
));
|
||||
debug!("deduce_sig_from_projection: sig={:?}", sig);
|
||||
debug!(?sig);
|
||||
|
||||
Some(ExpectedSig { cause_span, sig })
|
||||
}
|
||||
|
@ -401,9 +422,14 @@ 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(),
|
||||
sig.output(),
|
||||
output,
|
||||
sig.c_variadic,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::RustCall,
|
||||
|
@ -590,6 +616,8 @@ 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(
|
||||
|
@ -610,27 +638,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
result
|
||||
}
|
||||
|
||||
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, self.param_env);
|
||||
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>> {
|
||||
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 ret_vid = match *ret_ty.kind() {
|
||||
ty::Infer(ty::TyVar(ret_vid)) => ret_vid,
|
||||
let (def_id, substs) = match *ret_ty.kind() {
|
||||
ty::Opaque(def_id, substs) => (def_id, substs),
|
||||
ty::Error(_) => return None,
|
||||
_ => span_bug!(
|
||||
self.tcx.def_span(expr_def_id),
|
||||
|
@ -638,17 +668,19 @@ 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 = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
|
||||
let bound_predicate = obligation.predicate.kind();
|
||||
let output_ty = item_bounds.iter().find_map(|&(predicate, span)| {
|
||||
let bound_predicate = predicate.subst(self.tcx, substs).kind();
|
||||
if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
|
||||
self.deduce_future_output_from_projection(
|
||||
obligation.cause.span,
|
||||
span,
|
||||
bound_predicate.rebind(proj_predicate),
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -1272,7 +1272,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.final()`, which will return
|
||||
/// isn't *final* until you call `self.complete()`, which will return
|
||||
/// the merged type.
|
||||
pub fn merged_ty(&self) -> Ty<'tcx> {
|
||||
self.final_ty.unwrap_or(self.expected_ty)
|
||||
|
|
|
@ -965,8 +965,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
let else_diverges = self.diverges.get();
|
||||
|
||||
let opt_suggest_box_span =
|
||||
self.opt_suggest_box_span(else_expr.span, else_ty, orig_expected);
|
||||
let opt_suggest_box_span = self.opt_suggest_box_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 varibales. If not, no need for fallback.
|
||||
// Check if we have any unsolved variables. If not, no need for fallback.
|
||||
let unsolved_variables = self.unsolved_variables();
|
||||
if unsolved_variables.is_empty() {
|
||||
return false;
|
||||
|
@ -66,16 +66,6 @@ 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
|
||||
}
|
||||
|
||||
|
@ -136,59 +126,6 @@ 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.
|
||||
|
|
|
@ -372,23 +372,6 @@ 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
|
||||
|
@ -775,6 +758,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) -> Vec<Ty<'tcx>> {
|
||||
let formal_ret = self.resolve_vars_with_obligations(formal_ret);
|
||||
let Some(ret_ty) = expected_ret.only_has_type(self) else { return Vec::new() };
|
||||
|
||||
// HACK(oli-obk): This is a hack to keep RPIT and TAIT in sync wrt their behaviour.
|
||||
// Without it, the inference
|
||||
// variable will get instantiated with the opaque type. The inference variable often
|
||||
// has various helpful obligations registered for it that help closures figure out their
|
||||
// signature. If we infer the inference var to the opaque type, the closure won't be able
|
||||
// to find those obligations anymore, and it can't necessarily find them from the opaque
|
||||
// type itself. We could be more powerful with inference if we *combined* the obligations
|
||||
// so that we got both the obligations from the opaque type and the ones from the inference
|
||||
// variable. That will accept more code than we do right now, so we need to carefully consider
|
||||
// the implications.
|
||||
// Note: this check is pessimistic, as the inference type could be matched with something other
|
||||
// than the opaque type, but then we need a new `TypeRelation` just for this specific case and
|
||||
// can't re-use `sup` below.
|
||||
// See src/test/ui/impl-trait/hidden-type-is-opaque.rs and
|
||||
// src/test/ui/impl-trait/hidden-type-is-opaque-2.rs for examples that hit this path.
|
||||
if formal_ret.has_infer_types() {
|
||||
for ty in ret_ty.walk() {
|
||||
if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() {
|
||||
if let ty::Opaque(def_id, _) = *ty.kind() {
|
||||
if self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() {
|
||||
return Vec::new();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let expect_args = self
|
||||
.fudge_inference_if_ok(|| {
|
||||
// Attempt to apply a subtyping relationship between the formal
|
||||
|
|
|
@ -57,8 +57,6 @@ 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
|
||||
|
@ -130,7 +128,6 @@ 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,6 +95,13 @@ 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> {
|
||||
|
@ -119,8 +126,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);
|
||||
}
|
||||
|
|
|
@ -1476,6 +1476,7 @@ 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))) => {
|
||||
|
@ -1505,6 +1506,7 @@ 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,
|
||||
|
@ -1655,6 +1657,7 @@ 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()
|
||||
{
|
||||
|
|
|
@ -343,6 +343,7 @@ 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,11 +335,6 @@ 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)
|
||||
|
|
|
@ -968,7 +968,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),
|
||||
inherited: Inherited::build(tcx, def_id).reveal_defining_opaque_types(),
|
||||
id: hir::HirId::make_owner(def_id),
|
||||
span,
|
||||
param_env: tcx.param_env(def_id),
|
||||
|
|
|
@ -18,9 +18,9 @@ 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;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Entry point
|
||||
|
@ -65,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(body.value.span);
|
||||
wbcx.visit_opaque_types();
|
||||
wbcx.visit_coercion_casts();
|
||||
wbcx.visit_user_provided_tys();
|
||||
wbcx.visit_user_provided_sigs();
|
||||
|
@ -497,64 +497,39 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
fcx_typeck_results.generator_interior_types.clone();
|
||||
}
|
||||
|
||||
#[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;
|
||||
#[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(_) => {
|
||||
let ty = self.resolve(decl.hidden_type.ty, &decl.hidden_type.span);
|
||||
struct RecursionChecker {
|
||||
def_id: DefId,
|
||||
}
|
||||
impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker {
|
||||
type BreakTy = ();
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if let ty::Opaque(def_id, _) = *t.kind() {
|
||||
if def_id == self.def_id {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
if ty
|
||||
.visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
|
||||
.is_break()
|
||||
{
|
||||
return;
|
||||
}
|
||||
Some(ty)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
hir::OpaqueTyOrigin::TyAlias => None,
|
||||
};
|
||||
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hir::{HirId, Node};
|
|||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
|
@ -358,29 +358,24 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
.concrete_opaque_types
|
||||
.get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
|
||||
.copied()
|
||||
.map(|concrete| concrete.ty)
|
||||
.unwrap_or_else(|| {
|
||||
tcx.sess.delay_span_bug(
|
||||
DUMMY_SP,
|
||||
&format!(
|
||||
"owner {:?} has no opaque type for {:?} in its typeck results",
|
||||
owner, def_id,
|
||||
),
|
||||
);
|
||||
if let Some(_) =
|
||||
tcx.typeck(owner).tainted_by_errors
|
||||
{
|
||||
let table = tcx.typeck(owner);
|
||||
if let Some(_) = table.tainted_by_errors {
|
||||
// Some error in the
|
||||
// owner fn prevented us from populating
|
||||
// the `concrete_opaque_types` table.
|
||||
tcx.ty_error()
|
||||
} else {
|
||||
// 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()),
|
||||
)
|
||||
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")
|
||||
}
|
||||
});
|
||||
debug!("concrete_ty = {:?}", concrete_ty);
|
||||
|
@ -562,7 +557,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
/// with the first type that we find, and then later types are
|
||||
/// checked against it (we also carry the span of that first
|
||||
/// type).
|
||||
found: Option<(Span, Ty<'tcx>)>,
|
||||
found: Option<ty::OpaqueHiddenType<'tcx>>,
|
||||
}
|
||||
|
||||
impl ConstraintLocator<'_> {
|
||||
|
@ -575,14 +570,28 @@ 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.
|
||||
if !self.tcx.typeck(def_id).concrete_opaque_types.contains(&self.def_id) {
|
||||
// ```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(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error() });
|
||||
return;
|
||||
}
|
||||
if tables.concrete_opaque_types.get(&self.def_id).is_none() {
|
||||
debug!("no constraints in typeck results");
|
||||
return;
|
||||
}
|
||||
// Use borrowck to get the type with unerased regions.
|
||||
let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
|
||||
debug!(?concrete_opaque_types);
|
||||
for (opaque_type_key, concrete_type) in concrete_opaque_types {
|
||||
for &(opaque_type_key, concrete_type) in concrete_opaque_types {
|
||||
if opaque_type_key.def_id != self.def_id {
|
||||
// Ignore constraints for other opaque types.
|
||||
continue;
|
||||
|
@ -590,26 +599,26 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
|
||||
debug!(?concrete_type, ?opaque_type_key.substs, "found constraint");
|
||||
|
||||
// FIXME(oli-obk): trace the actual span from inference to improve errors.
|
||||
let span = self.tcx.def_span(def_id);
|
||||
|
||||
if let Some((prev_span, prev_ty)) = self.found {
|
||||
if *concrete_type != prev_ty && !(*concrete_type, prev_ty).references_error() {
|
||||
debug!(?span);
|
||||
if let Some(prev) = self.found {
|
||||
if concrete_type.ty != prev.ty && !(concrete_type, prev).references_error() {
|
||||
// Found different concrete types for the opaque type.
|
||||
let mut err = self.tcx.sess.struct_span_err(
|
||||
span,
|
||||
concrete_type.span,
|
||||
"concrete type differs from previous defining opaque type use",
|
||||
);
|
||||
err.span_label(
|
||||
span,
|
||||
format!("expected `{}`, got `{}`", prev_ty, concrete_type),
|
||||
concrete_type.span,
|
||||
format!("expected `{}`, got `{}`", prev.ty, concrete_type.ty),
|
||||
);
|
||||
err.span_note(prev_span, "previous use here");
|
||||
if prev.span == concrete_type.span {
|
||||
err.span_label(prev.span, "this expression supplies two conflicting concrete types for the same opaque type");
|
||||
} else {
|
||||
err.span_note(prev.span, "previous use here");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
} else {
|
||||
self.found = Some((span, *concrete_type));
|
||||
self.found = Some(concrete_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -629,7 +638,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>) {
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
trace!(?it.def_id);
|
||||
// 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);
|
||||
|
@ -637,7 +646,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
}
|
||||
}
|
||||
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
trace!(?it.def_id);
|
||||
// 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);
|
||||
|
@ -645,7 +654,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
}
|
||||
}
|
||||
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
trace!(?it.def_id);
|
||||
self.check(it.def_id);
|
||||
intravisit::walk_trait_item(self, it);
|
||||
}
|
||||
|
@ -655,12 +664,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!("find_opaque_ty_constraints: scope={:?}", scope);
|
||||
debug!(?scope);
|
||||
|
||||
if scope == hir::CRATE_HIR_ID {
|
||||
tcx.hir().walk_toplevel_module(&mut locator);
|
||||
} else {
|
||||
debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
|
||||
trace!("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
|
||||
|
@ -684,10 +693,15 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
}
|
||||
|
||||
match locator.found {
|
||||
Some((_, ty)) => ty,
|
||||
Some(hidden) => hidden.ty,
|
||||
None => {
|
||||
let span = tcx.def_span(def_id);
|
||||
tcx.sess.span_err(span, "could not find defining uses");
|
||||
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.ty_error()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue