1
Fork 0

Auto merge of #120767 - matthiaskrgr:rollup-0k8ib1c, r=matthiaskrgr

Rollup of 9 pull requests

Successful merges:

 - #119592 (resolve: Unload speculatively resolved crates before freezing cstore)
 - #120103 (Make it so that async-fn-in-trait is compatible with a concrete future in implementation)
 - #120206 (hir: Make sure all `HirId`s have corresponding HIR `Node`s)
 - #120214 (match lowering: consistently lower bindings deepest-first)
 - #120688 (GVN: also turn moves into copies with projections)
 - #120702 (docs: also check the inline stmt during redundant link check)
 - #120727 (exhaustiveness: Prefer "`0..MAX` not covered" to "`_` not covered")
 - #120734 (Add `SubdiagnosticMessageOp` as a trait alias.)
 - #120739 (improve pretty printing for associated items in trait objects)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-02-08 12:14:19 +00:00
commit 1280928a99
125 changed files with 1562 additions and 999 deletions

View file

@ -1,5 +1,5 @@
use super::potentially_plural_count;
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture};
use hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
@ -10,7 +10,7 @@ use rustc_hir::{GenericParamKind, ImplItemKind};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_infer::traits::{util, FulfillmentError};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::util::ExplicitSelf;
@ -74,7 +74,6 @@ fn check_method_is_structurally_compatible<'tcx>(
compare_generic_param_kinds(tcx, impl_m, trait_m, delay)?;
compare_number_of_method_arguments(tcx, impl_m, trait_m, delay)?;
compare_synthetic_generics(tcx, impl_m, trait_m, delay)?;
compare_asyncness(tcx, impl_m, trait_m, delay)?;
check_region_bounds_on_impl_item(tcx, impl_m, trait_m, delay)?;
Ok(())
}
@ -414,36 +413,6 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> {
}
}
fn compare_asyncness<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: ty::AssocItem,
trait_m: ty::AssocItem,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
if tcx.asyncness(trait_m.def_id).is_async() {
match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() {
ty::Alias(ty::Opaque, ..) => {
// allow both `async fn foo()` and `fn foo() -> impl Future`
}
ty::Error(_) => {
// We don't know if it's ok, but at least it's already an error.
}
_ => {
return Err(tcx
.dcx()
.create_err(crate::errors::AsyncTraitImplShouldBeAsync {
span: tcx.def_span(impl_m.def_id),
method_name: trait_m.name,
trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
})
.emit_unless(delay));
}
};
}
Ok(())
}
/// Given a method def-id in an impl, compare the method signature of the impl
/// against the trait that it's implementing. In doing so, infer the hidden types
/// that this method's signature provides to satisfy each return-position `impl Trait`
@ -695,8 +664,13 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// RPITs.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
let reported = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(reported);
if let Err(guar) = try_report_async_mismatch(tcx, infcx, &errors, trait_m, impl_m, impl_sig)
{
return Err(guar);
}
let guar = infcx.err_ctxt().report_fulfillment_errors(errors);
return Err(guar);
}
// Finally, resolve all regions. This catches wily misuses of
@ -2252,3 +2226,47 @@ fn assoc_item_kind_str(impl_item: &ty::AssocItem) -> &'static str {
ty::AssocKind::Type => "type",
}
}
/// Manually check here that `async fn foo()` wasn't matched against `fn foo()`,
/// and extract a better error if so.
fn try_report_async_mismatch<'tcx>(
tcx: TyCtxt<'tcx>,
infcx: &InferCtxt<'tcx>,
errors: &[FulfillmentError<'tcx>],
trait_m: ty::AssocItem,
impl_m: ty::AssocItem,
impl_sig: ty::FnSig<'tcx>,
) -> Result<(), ErrorGuaranteed> {
if !tcx.asyncness(trait_m.def_id).is_async() {
return Ok(());
}
let ty::Alias(ty::Projection, ty::AliasTy { def_id: async_future_def_id, .. }) =
*tcx.fn_sig(trait_m.def_id).skip_binder().skip_binder().output().kind()
else {
bug!("expected `async fn` to return an RPITIT");
};
for error in errors {
if let traits::BindingObligation(def_id, _) = *error.root_obligation.cause.code()
&& def_id == async_future_def_id
&& let Some(proj) = error.root_obligation.predicate.to_opt_poly_projection_pred()
&& let Some(proj) = proj.no_bound_vars()
&& infcx.can_eq(
error.root_obligation.param_env,
proj.term.ty().unwrap(),
impl_sig.output(),
)
{
// FIXME: We should suggest making the fn `async`, but extracting
// the right span is a bit difficult.
return Err(tcx.sess.dcx().emit_err(MethodShouldReturnFuture {
span: tcx.def_span(impl_m.def_id),
method_name: trait_m.name,
trait_item_span: tcx.hir().span_if_local(trait_m.def_id),
}));
}
}
Ok(())
}

View file

@ -43,8 +43,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
return None;
}
let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
match tcx.opt_hir_node(hir_id) {
Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => {
match tcx.hir_node(hir_id) {
Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) => {
generics.params.is_empty().not().then_some(generics.span)
}
_ => {
@ -58,8 +58,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
return None;
}
let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
match tcx.opt_hir_node(hir_id) {
Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => {
match tcx.hir_node(hir_id) {
Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) => {
Some(generics.where_clause_span)
}
_ => {
@ -80,8 +80,8 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
return None;
}
let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local());
match tcx.opt_hir_node(hir_id) {
Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. })) => {
match tcx.hir_node(hir_id) {
Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. }) => {
Some(fn_sig.decl.output.span())
}
_ => {
@ -202,7 +202,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
let start_t = tcx.type_of(start_def_id).instantiate_identity();
match start_t.kind() {
ty::FnDef(..) => {
if let Some(Node::Item(it)) = tcx.opt_hir_node(start_id) {
if let Node::Item(it) = tcx.hir_node(start_id) {
if let hir::ItemKind::Fn(sig, generics, _) = &it.kind {
let mut error = false;
if !generics.params.is_empty() {

View file

@ -521,6 +521,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
},
Node::ArrayLenInfer(_) => tcx.types.usize,
x => {
bug!("unexpected sort of node in type_of(): {:?}", x);
}

View file

@ -166,17 +166,6 @@ pub struct LifetimesOrBoundsMismatchOnTrait {
pub ident: Ident,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_async_trait_impl_should_be_async)]
pub struct AsyncTraitImplShouldBeAsync {
#[primary_span]
// #[label]
pub span: Span,
#[label(hir_analysis_trait_item_label)]
pub trait_item_span: Option<Span>,
pub method_name: Symbol,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_drop_impl_on_wrong_item, code = E0120)]
pub struct DropImplOnWrongItem {
@ -1512,6 +1501,16 @@ pub struct NotSupportedDelegation<'a> {
pub callee_span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_method_should_return_future)]
pub struct MethodShouldReturnFuture {
#[primary_span]
pub span: Span,
pub method_name: Symbol,
#[note]
pub trait_item_span: Option<Span>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_unused_generic_parameter)]
pub(crate) struct UnusedGenericParameter {

View file

@ -771,8 +771,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
);
if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
&& let Some(parent_node) = self.tcx.opt_hir_node(parent_node)
&& let hir::Node::Expr(expr) = parent_node
&& let hir::Node::Expr(expr) = self.tcx.hir_node(parent_node)
{
match &expr.kind {
hir::ExprKind::Path(qpath) => self