Auto merge of #117415 - matthiaskrgr:rollup-jr2p1t2, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #116862 (Detect when trait is implemented for type and suggest importing it)
 - #117389 (Some diagnostics improvements of `gen` blocks)
 - #117396 (Don't treat closures/coroutine types as part of the public API)
 - #117398 (Correctly handle nested or-patterns in exhaustiveness)
 - #117403 (Poison check_well_formed if method receivers are invalid to prevent typeck from running on it)
 - #117411 (Improve some diagnostics around `?Trait` bounds)
 - #117414 (Don't normalize to an un-revealed opaque when we hit the recursion limit)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-10-30 20:50:14 +00:00
commit 31bc7e2c47
31 changed files with 288 additions and 151 deletions

View File

@ -8,6 +8,7 @@ use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::{ErrorGuaranteed, Span}; use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits; use rustc_trait_selection::traits;
use smallvec::SmallVec;
use crate::astconv::{ use crate::astconv::{
AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter, AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
@ -28,15 +29,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let tcx = self.tcx(); let tcx = self.tcx();
// Try to find an unbound in bounds. // Try to find an unbound in bounds.
let mut unbound = None; let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| { let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
for ab in ast_bounds { for ab in ast_bounds {
if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab { if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
if unbound.is_none() { unbounds.push(ptr)
unbound = Some(&ptr.trait_ref);
} else {
tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds { span });
}
} }
} }
}; };
@ -51,33 +48,41 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
} }
} }
let sized_def_id = tcx.lang_items().sized_trait(); if unbounds.len() > 1 {
match (&sized_def_id, unbound) { tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds {
(Some(sized_def_id), Some(tpb)) spans: unbounds.iter().map(|ptr| ptr.span).collect(),
if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) => });
{
// There was in fact a `?Sized` bound, return without doing anything
return;
}
(_, Some(_)) => {
// There was a `?Trait` bound, but it was not `?Sized`; warn.
tcx.sess.span_warn(
span,
"default bound relaxed for a type parameter, but \
this does nothing because the given bound is not \
a default; only `?Sized` is supported",
);
// Otherwise, add implicitly sized if `Sized` is available.
}
_ => {
// There was no `?Sized` bound; add implicitly sized if `Sized` is available.
}
} }
let sized_def_id = tcx.lang_items().sized_trait();
let mut seen_sized_unbound = false;
for unbound in unbounds {
if let Some(sized_def_id) = sized_def_id {
if unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) {
seen_sized_unbound = true;
continue;
}
}
// There was a `?Trait` bound, but it was not `?Sized`; warn.
tcx.sess.span_warn(
unbound.span,
"relaxing a default bound only does something for `?Sized`; \
all other traits are not bound by default",
);
}
// If the above loop finished there was no `?Sized` bound; add implicitly sized if `Sized` is available.
if sized_def_id.is_none() { if sized_def_id.is_none() {
// No lang item for `Sized`, so we can't add it as a bound. // No lang item for `Sized`, so we can't add it as a bound.
return; return;
} }
bounds.push_sized(tcx, self_ty, span); if seen_sized_unbound {
// There was in fact a `?Sized` bound, return without doing anything
} else {
// There was no `?Sized` bound; add implicitly sized if `Sized` is available.
bounds.push_sized(tcx, self_ty, span);
}
} }
/// This helper takes a *converted* parameter type (`param_ty`) /// This helper takes a *converted* parameter type (`param_ty`)

View File

@ -94,7 +94,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
f: F, f: F,
) -> Result<(), ErrorGuaranteed> ) -> Result<(), ErrorGuaranteed>
where where
F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>), F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> Result<(), ErrorGuaranteed>,
{ {
let param_env = tcx.param_env(body_def_id); let param_env = tcx.param_env(body_def_id);
let infcx = &tcx.infer_ctxt().build(); let infcx = &tcx.infer_ctxt().build();
@ -105,7 +105,7 @@ where
if !tcx.features().trivial_bounds { if !tcx.features().trivial_bounds {
wfcx.check_false_global_bounds() wfcx.check_false_global_bounds()
} }
f(&mut wfcx); f(&mut wfcx)?;
let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?; let assumed_wf_types = wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)?;
@ -875,6 +875,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
ty, ty,
trait_def_id, trait_def_id,
); );
Ok(())
}) })
} else { } else {
let mut diag = match ty.kind() { let mut diag = match ty.kind() {
@ -961,6 +962,7 @@ fn check_associated_item(
let ty = tcx.type_of(item.def_id).instantiate_identity(); let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into()); wfcx.register_wf_obligation(span, loc, ty.into());
Ok(())
} }
ty::AssocKind::Fn => { ty::AssocKind::Fn => {
let sig = tcx.fn_sig(item.def_id).instantiate_identity(); let sig = tcx.fn_sig(item.def_id).instantiate_identity();
@ -972,7 +974,7 @@ fn check_associated_item(
hir_sig.decl, hir_sig.decl,
item.def_id.expect_local(), item.def_id.expect_local(),
); );
check_method_receiver(wfcx, hir_sig, item, self_ty); check_method_receiver(wfcx, hir_sig, item, self_ty)
} }
ty::AssocKind::Type => { ty::AssocKind::Type => {
if let ty::AssocItemContainer::TraitContainer = item.container { if let ty::AssocItemContainer::TraitContainer = item.container {
@ -983,6 +985,7 @@ fn check_associated_item(
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into()); wfcx.register_wf_obligation(span, loc, ty.into());
} }
Ok(())
} }
} }
}) })
@ -1097,6 +1100,7 @@ fn check_type_defn<'tcx>(
} }
check_where_clauses(wfcx, item.span, item.owner_id.def_id); check_where_clauses(wfcx, item.span, item.owner_id.def_id);
Ok(())
}) })
} }
@ -1121,7 +1125,8 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuarant
} }
let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| {
check_where_clauses(wfcx, item.span, def_id) check_where_clauses(wfcx, item.span, def_id);
Ok(())
}); });
// Only check traits, don't check trait aliases // Only check traits, don't check trait aliases
@ -1164,6 +1169,7 @@ fn check_item_fn(
enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| { enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| {
let sig = tcx.fn_sig(def_id).instantiate_identity(); let sig = tcx.fn_sig(def_id).instantiate_identity();
check_fn_or_method(wfcx, ident.span, sig, decl, def_id); check_fn_or_method(wfcx, ident.span, sig, decl, def_id);
Ok(())
}) })
} }
@ -1218,6 +1224,7 @@ fn check_item_type(
tcx.require_lang_item(LangItem::Sync, Some(ty_span)), tcx.require_lang_item(LangItem::Sync, Some(ty_span)),
); );
} }
Ok(())
}) })
} }
@ -1276,6 +1283,7 @@ fn check_impl<'tcx>(
} }
check_where_clauses(wfcx, item.span, item.owner_id.def_id); check_where_clauses(wfcx, item.span, item.owner_id.def_id);
Ok(())
}) })
} }
@ -1548,11 +1556,11 @@ fn check_method_receiver<'tcx>(
fn_sig: &hir::FnSig<'_>, fn_sig: &hir::FnSig<'_>,
method: ty::AssocItem, method: ty::AssocItem,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
) { ) -> Result<(), ErrorGuaranteed> {
let tcx = wfcx.tcx(); let tcx = wfcx.tcx();
if !method.fn_has_self_parameter { if !method.fn_has_self_parameter {
return; return Ok(());
} }
let span = fn_sig.decl.inputs[0].span; let span = fn_sig.decl.inputs[0].span;
@ -1571,11 +1579,11 @@ fn check_method_receiver<'tcx>(
if tcx.features().arbitrary_self_types { if tcx.features().arbitrary_self_types {
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
// Report error; `arbitrary_self_types` was enabled. // Report error; `arbitrary_self_types` was enabled.
e0307(tcx, span, receiver_ty); return Err(e0307(tcx, span, receiver_ty));
} }
} else { } else {
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) { if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) {
if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { return Err(if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
// Report error; would have worked with `arbitrary_self_types`. // Report error; would have worked with `arbitrary_self_types`.
feature_err( feature_err(
&tcx.sess.parse_sess, &tcx.sess.parse_sess,
@ -1587,16 +1595,17 @@ fn check_method_receiver<'tcx>(
), ),
) )
.help(HELP_FOR_SELF_TYPE) .help(HELP_FOR_SELF_TYPE)
.emit(); .emit()
} else { } else {
// Report error; would not have worked with `arbitrary_self_types`. // Report error; would not have worked with `arbitrary_self_types`.
e0307(tcx, span, receiver_ty); e0307(tcx, span, receiver_ty)
} });
} }
} }
Ok(())
} }
fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) { fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) -> ErrorGuaranteed {
struct_span_err!( struct_span_err!(
tcx.sess.diagnostic(), tcx.sess.diagnostic(),
span, span,
@ -1605,7 +1614,7 @@ fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) {
) )
.note("type of `self` must be `Self` or a type that dereferences to it") .note("type of `self` must be `Self` or a type that dereferences to it")
.help(HELP_FOR_SELF_TYPE) .help(HELP_FOR_SELF_TYPE)
.emit(); .emit()
} }
/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If

View File

@ -96,7 +96,7 @@ pub struct CopyImplOnTypeWithDtor {
#[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")] #[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")]
pub struct MultipleRelaxedDefaultBounds { pub struct MultipleRelaxedDefaultBounds {
#[primary_span] #[primary_span]
pub span: Span, pub spans: Vec<Span>,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]

View File

@ -35,6 +35,7 @@ use rustc_span::def_id::DefIdSet;
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol; use rustc_span::Symbol;
use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span}; use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote; use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _; use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@ -192,7 +193,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.span_if_local(def_id) .span_if_local(def_id)
.unwrap_or_else(|| self.tcx.def_span(def_id)); .unwrap_or_else(|| self.tcx.def_span(def_id));
err.span_label(sp, format!("private {kind} defined here")); err.span_label(sp, format!("private {kind} defined here"));
self.suggest_valid_traits(&mut err, out_of_scope_traits); self.suggest_valid_traits(&mut err, out_of_scope_traits, true);
err.emit(); err.emit();
} }
@ -2464,6 +2465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self, &self,
err: &mut Diagnostic, err: &mut Diagnostic,
valid_out_of_scope_traits: Vec<DefId>, valid_out_of_scope_traits: Vec<DefId>,
explain: bool,
) -> bool { ) -> bool {
if !valid_out_of_scope_traits.is_empty() { if !valid_out_of_scope_traits.is_empty() {
let mut candidates = valid_out_of_scope_traits; let mut candidates = valid_out_of_scope_traits;
@ -2476,7 +2478,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did)) .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
.copied(); .copied();
err.help("items from traits can only be used if the trait is in scope"); if explain {
err.help("items from traits can only be used if the trait is in scope");
}
let msg = format!( let msg = format!(
"the following {traits_are} implemented but not in scope; \ "the following {traits_are} implemented but not in scope; \
perhaps add a `use` for {one_of_them}:", perhaps add a `use` for {one_of_them}:",
@ -2693,7 +2697,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
} }
if self.suggest_valid_traits(err, valid_out_of_scope_traits) { if self.suggest_valid_traits(err, valid_out_of_scope_traits, true) {
return; return;
} }
@ -2970,22 +2974,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(candidates, Vec::new()) (candidates, Vec::new())
}; };
let impls_trait = |def_id: DefId| {
let args = ty::GenericArgs::for_item(self.tcx, def_id, |param, _| {
if param.index == 0 {
rcvr_ty.into()
} else {
self.infcx.var_for_def(span, param)
}
});
self.infcx
.type_implements_trait(def_id, args, self.param_env)
.must_apply_modulo_regions()
&& param_type.is_none()
};
match &potential_candidates[..] { match &potential_candidates[..] {
[] => {} [] => {}
[trait_info] if trait_info.def_id.is_local() => { [trait_info] if trait_info.def_id.is_local() => {
err.subdiagnostic(CandidateTraitNote { if impls_trait(trait_info.def_id) {
span: self.tcx.def_span(trait_info.def_id), self.suggest_valid_traits(err, vec![trait_info.def_id], false);
trait_name: self.tcx.def_path_str(trait_info.def_id), } else {
item_name, err.subdiagnostic(CandidateTraitNote {
action_or_ty: if trait_missing_method { span: self.tcx.def_span(trait_info.def_id),
"NONE".to_string() trait_name: self.tcx.def_path_str(trait_info.def_id),
} else { item_name,
param_type.map_or_else( action_or_ty: if trait_missing_method {
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. "NONE".to_string()
ToString::to_string, } else {
) param_type.map_or_else(
}, || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
}); ToString::to_string,
)
},
});
}
} }
trait_infos => { trait_infos => {
let mut msg = message(param_type.map_or_else( let mut msg = message(param_type.map_or_else(
@ -2993,6 +3014,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|param| format!("restrict type parameter `{param}` with"), |param| format!("restrict type parameter `{param}` with"),
)); ));
for (i, trait_info) in trait_infos.iter().enumerate() { for (i, trait_info) in trait_infos.iter().enumerate() {
if impls_trait(trait_info.def_id) {
self.suggest_valid_traits(err, vec![trait_info.def_id], false);
}
msg.push_str(&format!( msg.push_str(&format!(
"\ncandidate #{}: `{}`", "\ncandidate #{}: `{}`",
i + 1, i + 1,

View File

@ -12,6 +12,8 @@ middle_assert_coroutine_resume_after_return = coroutine resumed after completion
middle_assert_divide_by_zero = middle_assert_divide_by_zero =
attempt to divide `{$val}` by zero attempt to divide `{$val}` by zero
middle_assert_gen_resume_after_panic = `gen` fn or block cannot be further iterated on after it panicked
middle_assert_misaligned_ptr_deref = middle_assert_misaligned_ptr_deref =
misaligned pointer dereference: address must be a multiple of {$required} but is {$found} misaligned pointer dereference: address must be a multiple of {$required} but is {$found}

View File

@ -250,8 +250,7 @@ impl<O> AssertKind<O> {
middle_assert_coroutine_resume_after_return middle_assert_coroutine_resume_after_return
} }
ResumedAfterPanic(CoroutineKind::Async(_)) => middle_assert_async_resume_after_panic, ResumedAfterPanic(CoroutineKind::Async(_)) => middle_assert_async_resume_after_panic,
// FIXME(gen_blocks): custom error message for `gen` blocks ResumedAfterPanic(CoroutineKind::Gen(_)) => middle_assert_gen_resume_after_panic,
ResumedAfterPanic(CoroutineKind::Gen(_)) => middle_assert_async_resume_after_panic,
ResumedAfterPanic(CoroutineKind::Coroutine) => { ResumedAfterPanic(CoroutineKind::Coroutine) => {
middle_assert_coroutine_resume_after_panic middle_assert_coroutine_resume_after_panic
} }

View File

@ -931,7 +931,7 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
let specialized = pat.specialize(pcx, &ctor); let specialized = pat.specialize(pcx, &ctor);
for (subpat, column) in specialized.iter().zip(&mut specialized_columns) { for (subpat, column) in specialized.iter().zip(&mut specialized_columns) {
if subpat.is_or_pat() { if subpat.is_or_pat() {
column.patterns.extend(subpat.iter_fields()) column.patterns.extend(subpat.flatten_or_pat())
} else { } else {
column.patterns.push(subpat) column.patterns.push(subpat)
} }

View File

@ -278,8 +278,8 @@ parse_found_expr_would_be_stmt = expected expression, found `{$token}`
parse_function_body_equals_expr = function body cannot be `= expression;` parse_function_body_equals_expr = function body cannot be `= expression;`
.suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;` .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
parse_gen_block = `gen` blocks are not yet implemented parse_gen_fn = `gen` functions are not yet implemented
.help = only the keyword is reserved for now .help = for now you can use `gen {"{}"}` blocks and return `impl Iterator` instead
parse_generic_args_in_pat_require_turbofish_syntax = generic args in patterns require the turbofish syntax parse_generic_args_in_pat_require_turbofish_syntax = generic args in patterns require the turbofish syntax

View File

@ -521,9 +521,9 @@ pub(crate) struct CatchAfterTry {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(parse_gen_block)] #[diag(parse_gen_fn)]
#[help] #[help]
pub(crate) struct GenBlock { pub(crate) struct GenFn {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }

View File

@ -2372,7 +2372,7 @@ impl<'a> Parser<'a> {
} }
if let Gen::Yes { span, .. } = genness { if let Gen::Yes { span, .. } = genness {
self.sess.emit_err(errors::GenBlock { span }); self.sess.emit_err(errors::GenFn { span });
} }
if !self.eat_keyword_case(kw::Fn, case) { if !self.eat_keyword_case(kw::Fn, case) {

View File

@ -230,17 +230,14 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
Reveal::All => { Reveal::All => {
let args = data.args.try_fold_with(self)?; let args = data.args.try_fold_with(self)?;
let recursion_limit = self.interner().recursion_limit(); let recursion_limit = self.interner().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) { if !recursion_limit.value_within_limit(self.anon_depth) {
// A closure or coroutine may have itself as in its upvars. let guar = self
// This should be checked handled by the recursion check for opaque .infcx
// types, but we may end up here before that check can happen.
// In that case, we delay a bug to mark the trip, and continue without
// revealing the opaque.
self.infcx
.err_ctxt() .err_ctxt()
.build_overflow_error(&ty, self.cause.span, true) .build_overflow_error(&ty, self.cause.span, true)
.delay_as_bug(); .delay_as_bug();
return ty.try_super_fold_with(self); return Ok(Ty::new_error(self.interner(), guar));
} }
let generic_ty = self.interner().type_of(data.def_id); let generic_ty = self.interner().type_of(data.def_id);

View File

@ -121,6 +121,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
} }
impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> { impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> {
#[instrument(skip(self), ret, level = "trace")]
fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> { fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> {
self.visit_spanned(span, value); self.visit_spanned(span, value);
ControlFlow::Continue(()) ControlFlow::Continue(())

View File

@ -4,7 +4,7 @@
use std::ops::ControlFlow; use std::ops::ControlFlow;
use rustc_hir::{def::DefKind, def_id::LocalDefId}; use rustc_hir::{def::DefKind, def_id::LocalDefId};
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::TyCtxt;
use rustc_span::Span; use rustc_span::Span;
use rustc_type_ir::visit::TypeVisitable; use rustc_type_ir::visit::TypeVisitable;
@ -25,24 +25,9 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
let kind = tcx.def_kind(item); let kind = tcx.def_kind(item);
trace!(?kind); trace!(?kind);
match kind { match kind {
DefKind::Coroutine => { // Walk over the signature of the function
match tcx.type_of(item).instantiate_identity().kind() { DefKind::AssocFn | DefKind::Fn => {
ty::Coroutine(_, args, _) => visitor.visit(tcx.def_span(item), args.as_coroutine().sig())?, let ty_sig = tcx.fn_sig(item).instantiate_identity();
_ => bug!(),
}
for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
visitor.visit(span, pred)?;
}
}
// Walk over the signature of the function-like
DefKind::Closure | DefKind::AssocFn | DefKind::Fn => {
let ty_sig = match kind {
DefKind::Closure => match tcx.type_of(item).instantiate_identity().kind() {
ty::Closure(_, args) => args.as_closure().sig(),
_ => bug!(),
},
_ => tcx.fn_sig(item).instantiate_identity(),
};
let hir_sig = tcx.hir().get_by_def_id(item).fn_decl().unwrap(); let hir_sig = tcx.hir().get_by_def_id(item).fn_decl().unwrap();
// Walk over the inputs and outputs manually in order to get good spans for them. // Walk over the inputs and outputs manually in order to get good spans for them.
visitor.visit(hir_sig.output.span(), ty_sig.output()); visitor.visit(hir_sig.output.span(), ty_sig.output());
@ -61,7 +46,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
Some(ty) => ty.span, Some(ty) => ty.span,
_ => tcx.def_span(item), _ => tcx.def_span(item),
}; };
visitor.visit(span, tcx.type_of(item).instantiate_identity()); visitor.visit(span, tcx.type_of(item).instantiate_identity());
for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
visitor.visit(span, pred)?; visitor.visit(span, pred)?;
} }
@ -74,13 +59,15 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
// Look at field types // Look at field types
DefKind::Struct | DefKind::Union | DefKind::Enum => { DefKind::Struct | DefKind::Union | DefKind::Enum => {
let span = tcx.def_ident_span(item).unwrap(); let span = tcx.def_ident_span(item).unwrap();
visitor.visit(span, tcx.type_of(item).instantiate_identity()); visitor.visit(span, tcx.type_of(item).instantiate_identity());
for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
visitor.visit(span, pred)?; visitor.visit(span, pred)?;
} }
} }
// Does not have a syntactical signature // These are not part of a public API, they can only appear as hidden types, and there
DefKind::InlineConst => {} // the interesting parts are solely in the signature of the containing item's opaque type
// or dyn type.
DefKind::InlineConst | DefKind::Closure | DefKind::Coroutine => {}
DefKind::Impl { of_trait } => { DefKind::Impl { of_trait } => {
if of_trait { if of_trait {
let span = tcx.hir().get_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span; let span = tcx.hir().get_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span;
@ -92,15 +79,11 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
_ => tcx.def_span(item), _ => tcx.def_span(item),
}; };
visitor.visit(span, tcx.type_of(item).instantiate_identity()); visitor.visit(span, tcx.type_of(item).instantiate_identity());
for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
visitor.visit(span, pred)?;
}}
DefKind::Trait => {
for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
visitor.visit(span, pred)?; visitor.visit(span, pred)?;
} }
} }
DefKind::TraitAlias => { DefKind::TraitAlias | DefKind::Trait => {
for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) {
visitor.visit(span, pred)?; visitor.visit(span, pred)?;
} }

View File

@ -0,0 +1,26 @@
//compile-flags: --edition 2024 -Zunstable-options
// run-pass
// needs-unwind
#![feature(gen_blocks)]
fn main() {
let mut iter = gen {
yield 42;
panic!("foo");
yield 69; //~ WARN: unreachable statement
};
assert_eq!(iter.next(), Some(42));
let mut tmp = std::panic::AssertUnwindSafe(&mut iter);
match std::panic::catch_unwind(move || tmp.next()) {
Ok(_) => unreachable!(),
Err(err) => assert_eq!(*err.downcast::<&'static str>().unwrap(), "foo"),
}
match std::panic::catch_unwind(move || iter.next()) {
Ok(_) => unreachable!(),
Err(err) => assert_eq!(
*err.downcast::<&'static str>().unwrap(),
"`gen fn` should just keep returning `None` after panicking",
),
}
}

View File

@ -0,0 +1,12 @@
warning: unreachable statement
--> $DIR/gen_block_panic.rs:10:9
|
LL | panic!("foo");
| ------------- any code following this expression is unreachable
LL | yield 69;
| ^^^^^^^^^ unreachable statement
|
= note: `#[warn(unreachable_code)]` on by default
warning: 1 warning emitted

View File

@ -1,10 +1,10 @@
error: `gen` blocks are not yet implemented error: `gen` functions are not yet implemented
--> $DIR/gen_fn.rs:4:1 --> $DIR/gen_fn.rs:4:1
| |
LL | gen fn foo() {} LL | gen fn foo() {}
| ^^^ | ^^^
| |
= help: only the keyword is reserved for now = help: for now you can use `gen {}` blocks and return `impl Iterator` instead
error: aborting due to previous error error: aborting due to previous error

View File

@ -3,6 +3,6 @@
gen fn foo() {} gen fn foo() {}
//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen` //[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen`
//[e2024]~^^ ERROR: `gen` blocks are not yet implemented //[e2024]~^^ ERROR: `gen` functions are not yet implemented
fn main() {} fn main() {}

View File

@ -1,6 +1,6 @@
struct Foo<T: ?Hash> { } struct Foo<T: ?Hash> {}
//~^ ERROR expected trait, found derive macro `Hash` //~^ ERROR expected trait, found derive macro `Hash`
//~^^ ERROR parameter `T` is never used //~^^ ERROR parameter `T` is never used
//~^^^ WARN default bound relaxed for a type parameter, but this does nothing //~^^^ WARN relaxing a default bound only does something for `?Sized`
fn main() { } fn main() {}

View File

@ -1,7 +1,7 @@
error[E0404]: expected trait, found derive macro `Hash` error[E0404]: expected trait, found derive macro `Hash`
--> $DIR/issue-37534.rs:1:16 --> $DIR/issue-37534.rs:1:16
| |
LL | struct Foo<T: ?Hash> { } LL | struct Foo<T: ?Hash> {}
| ^^^^ not a trait | ^^^^ not a trait
| |
help: consider importing this trait instead help: consider importing this trait instead
@ -9,16 +9,16 @@ help: consider importing this trait instead
LL + use std::hash::Hash; LL + use std::hash::Hash;
| |
warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
--> $DIR/issue-37534.rs:1:12 --> $DIR/issue-37534.rs:1:15
| |
LL | struct Foo<T: ?Hash> { } LL | struct Foo<T: ?Hash> {}
| ^ | ^^^^^
error[E0392]: parameter `T` is never used error[E0392]: parameter `T` is never used
--> $DIR/issue-37534.rs:1:12 --> $DIR/issue-37534.rs:1:12
| |
LL | struct Foo<T: ?Hash> { } LL | struct Foo<T: ?Hash> {}
| ^ unused parameter | ^ unused parameter
| |
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`

View File

@ -6,11 +6,11 @@
// Check that these function definitions only emit warnings, not errors // Check that these function definitions only emit warnings, not errors
fn arg<T: ?Send>(_: T) {} fn arg<T: ?Send>(_: T) {}
//~^ warning: default bound relaxed for a type parameter, but this does nothing //~^ warning: relaxing a default bound only does something for `?Sized`
fn ref_arg<T: ?Send>(_: &T) {} fn ref_arg<T: ?Send>(_: &T) {}
//~^ warning: default bound relaxed for a type parameter, but this does nothing //~^ warning: relaxing a default bound only does something for `?Sized`
fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() } fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
//~^ warning: default bound relaxed for a type parameter, but this does nothing //~^ warning: relaxing a default bound only does something for `?Sized`
// Check that there's no `?Sized` relaxation! // Check that there's no `?Sized` relaxation!
fn main() { fn main() {

View File

@ -1,20 +1,20 @@
warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
--> $DIR/issue-87199.rs:8:8 --> $DIR/issue-87199.rs:8:11
| |
LL | fn arg<T: ?Send>(_: T) {} LL | fn arg<T: ?Send>(_: T) {}
| ^ | ^^^^^
warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
--> $DIR/issue-87199.rs:10:12 --> $DIR/issue-87199.rs:10:15
| |
LL | fn ref_arg<T: ?Send>(_: &T) {} LL | fn ref_arg<T: ?Send>(_: &T) {}
| ^ | ^^^^^
warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
--> $DIR/issue-87199.rs:12:13 --> $DIR/issue-87199.rs:12:40
| |
LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() } LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^
error[E0277]: the size for values of type `[i32]` cannot be known at compilation time error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
--> $DIR/issue-87199.rs:18:15 --> $DIR/issue-87199.rs:18:15

View File

@ -35,4 +35,10 @@ fn main() {
((0, 0) | (1, 0),) => {} ((0, 0) | (1, 0),) => {}
_ => {} _ => {}
} }
// This one caused ICE https://github.com/rust-lang/rust/issues/117378
match (0u8, 0) {
(x @ 0 | x @ (1 | 2), _) => {}
(3.., _) => {}
}
} }

View File

@ -0,0 +1,13 @@
error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature
--> $DIR/arbitrary-self-from-method-substs.rs:8:43
|
LL | fn get<R: Deref<Target = Self>>(self: R) -> u32 {
| ^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -1,5 +1,5 @@
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/arbitrary-self-from-method-substs.rs:14:5 --> $DIR/arbitrary-self-from-method-substs.rs:16:5
| |
LL | foo.get::<&Foo>(); LL | foo.get::<&Foo>();
| ^^^ expected `&Foo`, found `Foo` | ^^^ expected `&Foo`, found `Foo`

View File

@ -1,10 +1,12 @@
#![feature(arbitrary_self_types)] // revisions: default feature
#![cfg_attr(feature, feature(arbitrary_self_types))]
use std::ops::Deref; use std::ops::Deref;
struct Foo(u32); struct Foo(u32);
impl Foo { impl Foo {
fn get<R: Deref<Target=Self>>(self: R) -> u32 { fn get<R: Deref<Target = Self>>(self: R) -> u32 {
//[default]~^ ERROR: `R` cannot be used as the type of `self`
self.0 self.0
} }
} }
@ -12,5 +14,5 @@ impl Foo {
fn main() { fn main() {
let mut foo = Foo(1); let mut foo = Foo(1);
foo.get::<&Foo>(); foo.get::<&Foo>();
//~^ ERROR mismatched types //[feature]~^ ERROR mismatched types
} }

View File

@ -8,11 +8,10 @@ LL | S.a();
| ^ method not found in `S` | ^ method not found in `S`
| |
= help: items from traits can only be used if the trait is implemented and in scope = help: items from traits can only be used if the trait is implemented and in scope
note: `method::A` defines an item `a`, perhaps you need to implement it help: the following trait is implemented but not in scope; perhaps add a `use` for it:
--> $DIR/item-privacy.rs:6:5 |
LL + use method::A;
| |
LL | trait A {
| ^^^^^^^
error[E0599]: no method named `b` found for struct `S` in the current scope error[E0599]: no method named `b` found for struct `S` in the current scope
--> $DIR/item-privacy.rs:68:7 --> $DIR/item-privacy.rs:68:7
@ -51,11 +50,10 @@ LL | S::a(&S);
| ^ function or associated item not found in `S` | ^ function or associated item not found in `S`
| |
= help: items from traits can only be used if the trait is implemented and in scope = help: items from traits can only be used if the trait is implemented and in scope
note: `method::A` defines an item `a`, perhaps you need to implement it help: the following trait is implemented but not in scope; perhaps add a `use` for it:
--> $DIR/item-privacy.rs:6:5 |
LL + use method::A;
| |
LL | trait A {
| ^^^^^^^
error[E0599]: no function or associated item named `b` found for struct `S` in the current scope error[E0599]: no function or associated item named `b` found for struct `S` in the current scope
--> $DIR/item-privacy.rs:80:8 --> $DIR/item-privacy.rs:80:8
@ -91,11 +89,10 @@ LL | S::A;
| ^ associated item not found in `S` | ^ associated item not found in `S`
| |
= help: items from traits can only be used if the trait is implemented and in scope = help: items from traits can only be used if the trait is implemented and in scope
note: `assoc_const::A` defines an item `A`, perhaps you need to implement it help: the following trait is implemented but not in scope; perhaps add a `use` for it:
--> $DIR/item-privacy.rs:24:5 |
LL + use assoc_const::A;
| |
LL | trait A {
| ^^^^^^^
error[E0599]: no associated item named `B` found for struct `S` in the current scope error[E0599]: no associated item named `B` found for struct `S` in the current scope
--> $DIR/item-privacy.rs:98:8 --> $DIR/item-privacy.rs:98:8

View File

@ -0,0 +1,8 @@
#![feature(type_alias_impl_trait)]
type T = impl Copy;
//~^ ERROR cannot resolve opaque type
static STATIC: T = None::<&'static T>;
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0720]: cannot resolve opaque type
--> $DIR/infinite-cycle-involving-weak.rs:3:10
|
LL | type T = impl Copy;
| ^^^^^^^^^ cannot resolve opaque type
error: aborting due to previous error
For more information about this error, try `rustc --explain E0720`.

View File

@ -0,0 +1,44 @@
//! This test checks that we do not walk types in async blocks for
//! determining the opaque types that appear in a signature. async blocks,
//! all other coroutines and closures are always private and not part of
//! a signature. They become part of a signature via `dyn Trait` or `impl Trait`,
//! which is something that we process abstractly without looking at its hidden
//! types.
// edition: 2021
// check-pass
#![feature(impl_trait_in_assoc_type)]
use std::future::Future;
pub struct MemtableLocalStateStore {
mem_table: MemTable,
}
impl LocalStateStore for MemtableLocalStateStore {
type IterStream<'a> = impl Sized + 'a where Self: 'a;
fn iter(&self) -> impl Future<Output = Self::IterStream<'_>> + '_ {
async move { merge_stream(self.mem_table.iter()) }
}
}
trait LocalStateStore {
type IterStream<'a>
where
Self: 'a;
fn iter(&self) -> impl Future<Output = Self::IterStream<'_>> + '_;
}
struct MemTable;
impl MemTable {
fn iter<'a>(&'a self) -> impl Iterator<Item = &'a ()> {
std::iter::empty()
}
}
pub(crate) async fn merge_stream<'a>(mem_table_iter: impl Iterator<Item = &'a ()>) {}
fn main() {}

View File

@ -11,11 +11,11 @@ trait Trait<'a> {}
struct S4<T>(T) where for<'a> T: ?Trait<'a>; struct S4<T>(T) where for<'a> T: ?Trait<'a>;
//~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared //~^ ERROR `?Trait` bounds are only permitted at the point where a type parameter is declared
//~| WARN default bound relaxed for a type parameter //~| WARN relaxing a default bound only does something for `?Sized`
struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized; struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
//~^ ERROR type parameter has more than one relaxed default bound //~^ ERROR type parameter has more than one relaxed default bound
//~| WARN default bound relaxed for a type parameter //~| WARN relaxing a default bound only does something for `?Sized`
impl<T> S1<T> { impl<T> S1<T> {
fn f() where T: ?Sized {} fn f() where T: ?Sized {}

View File

@ -28,23 +28,23 @@ error: `?Trait` bounds are only permitted at the point where a type parameter is
LL | fn f() where T: ?Sized {} LL | fn f() where T: ?Sized {}
| ^^^^^^ | ^^^^^^
warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
--> $DIR/maybe-bounds-where.rs:12:11 --> $DIR/maybe-bounds-where.rs:12:34
| |
LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>; LL | struct S4<T>(T) where for<'a> T: ?Trait<'a>;
| ^ | ^^^^^^^^^^
error[E0203]: type parameter has more than one relaxed default bound, only one is supported error[E0203]: type parameter has more than one relaxed default bound, only one is supported
--> $DIR/maybe-bounds-where.rs:16:11 --> $DIR/maybe-bounds-where.rs:16:33
| |
LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized; LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
| ^ | ^^^^^^^^^^^^^^^ ^^^^^^
warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
--> $DIR/maybe-bounds-where.rs:16:11 --> $DIR/maybe-bounds-where.rs:16:33
| |
LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized; LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
| ^ | ^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors; 2 warnings emitted error: aborting due to 6 previous errors; 2 warnings emitted