Skip to content

Commit

Permalink
Auto merge of rust-lang#117415 - matthiaskrgr:rollup-jr2p1t2, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 7 pull requests

Successful merges:

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

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Oct 30, 2023
2 parents 236ac91 + c5aec96 commit 31bc7e2
Show file tree
Hide file tree
Showing 31 changed files with 286 additions and 149 deletions.
57 changes: 31 additions & 26 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
use rustc_span::symbol::Ident;
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits;
use smallvec::SmallVec;

use crate::astconv::{
AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
Expand All @@ -28,15 +29,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let tcx = self.tcx();

// 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>]| {
for ab in ast_bounds {
if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
if unbound.is_none() {
unbound = Some(&ptr.trait_ref);
} else {
tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds { span });
}
unbounds.push(ptr)
}
}
};
Expand All @@ -51,33 +48,41 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}
}

if unbounds.len() > 1 {
tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds {
spans: unbounds.iter().map(|ptr| ptr.span).collect(),
});
}

let sized_def_id = tcx.lang_items().sized_trait();
match (&sized_def_id, unbound) {
(Some(sized_def_id), Some(tpb))
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 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() {
// No lang item for `Sized`, so we can't add it as a bound.
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`)
Expand Down
35 changes: 22 additions & 13 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
f: F,
) -> Result<(), ErrorGuaranteed>
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 infcx = &tcx.infer_ctxt().build();
Expand All @@ -105,7 +105,7 @@ where
if !tcx.features().trivial_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)?;

Expand Down Expand Up @@ -875,6 +875,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
ty,
trait_def_id,
);
Ok(())
})
} else {
let mut diag = match ty.kind() {
Expand Down Expand Up @@ -961,6 +962,7 @@ fn check_associated_item(
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
Ok(())
}
ty::AssocKind::Fn => {
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
Expand All @@ -972,7 +974,7 @@ fn check_associated_item(
hir_sig.decl,
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 => {
if let ty::AssocItemContainer::TraitContainer = item.container {
Expand All @@ -983,6 +985,7 @@ fn check_associated_item(
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
}
Ok(())
}
}
})
Expand Down Expand Up @@ -1097,6 +1100,7 @@ fn check_type_defn<'tcx>(
}

check_where_clauses(wfcx, item.span, item.owner_id.def_id);
Ok(())
})
}

Expand All @@ -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| {
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
Expand Down Expand Up @@ -1164,6 +1169,7 @@ fn check_item_fn(
enter_wf_checking_ctxt(tcx, span, def_id, |wfcx| {
let sig = tcx.fn_sig(def_id).instantiate_identity();
check_fn_or_method(wfcx, ident.span, sig, decl, def_id);
Ok(())
})
}

Expand Down Expand Up @@ -1218,6 +1224,7 @@ fn check_item_type(
tcx.require_lang_item(LangItem::Sync, Some(ty_span)),
);
}
Ok(())
})
}

Expand Down Expand Up @@ -1276,6 +1283,7 @@ fn check_impl<'tcx>(
}

check_where_clauses(wfcx, item.span, item.owner_id.def_id);
Ok(())
})
}

Expand Down Expand Up @@ -1548,11 +1556,11 @@ fn check_method_receiver<'tcx>(
fn_sig: &hir::FnSig<'_>,
method: ty::AssocItem,
self_ty: Ty<'tcx>,
) {
) -> Result<(), ErrorGuaranteed> {
let tcx = wfcx.tcx();

if !method.fn_has_self_parameter {
return;
return Ok(());
}

let span = fn_sig.decl.inputs[0].span;
Expand All @@ -1571,11 +1579,11 @@ fn check_method_receiver<'tcx>(
if tcx.features().arbitrary_self_types {
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
// Report error; `arbitrary_self_types` was enabled.
e0307(tcx, span, receiver_ty);
return Err(e0307(tcx, span, receiver_ty));
}
} else {
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`.
feature_err(
&tcx.sess.parse_sess,
Expand All @@ -1587,16 +1595,17 @@ fn check_method_receiver<'tcx>(
),
)
.help(HELP_FOR_SELF_TYPE)
.emit();
.emit()
} else {
// 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!(
tcx.sess.diagnostic(),
span,
Expand All @@ -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")
.help(HELP_FOR_SELF_TYPE)
.emit();
.emit()
}

/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ pub struct CopyImplOnTypeWithDtor {
#[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")]
pub struct MultipleRelaxedDefaultBounds {
#[primary_span]
pub span: Span,
pub spans: Vec<Span>,
}

#[derive(Diagnostic)]
Expand Down
56 changes: 40 additions & 16 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use rustc_span::def_id::DefIdSet;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
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::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
Expand Down Expand Up @@ -192,7 +193,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.span_if_local(def_id)
.unwrap_or_else(|| self.tcx.def_span(def_id));
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();
}

Expand Down Expand Up @@ -2464,6 +2465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
err: &mut Diagnostic,
valid_out_of_scope_traits: Vec<DefId>,
explain: bool,
) -> bool {
if !valid_out_of_scope_traits.is_empty() {
let mut candidates = valid_out_of_scope_traits;
Expand All @@ -2476,7 +2478,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
.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!(
"the following {traits_are} implemented but not in scope; \
perhaps add a `use` for {one_of_them}:",
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -2970,29 +2974,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(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[..] {
[] => {}
[trait_info] if trait_info.def_id.is_local() => {
err.subdiagnostic(CandidateTraitNote {
span: self.tcx.def_span(trait_info.def_id),
trait_name: self.tcx.def_path_str(trait_info.def_id),
item_name,
action_or_ty: if trait_missing_method {
"NONE".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,
)
},
});
if impls_trait(trait_info.def_id) {
self.suggest_valid_traits(err, vec![trait_info.def_id], false);
} else {
err.subdiagnostic(CandidateTraitNote {
span: self.tcx.def_span(trait_info.def_id),
trait_name: self.tcx.def_path_str(trait_info.def_id),
item_name,
action_or_ty: if trait_missing_method {
"NONE".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 => {
let mut msg = message(param_type.map_or_else(
|| "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
|param| format!("restrict type parameter `{param}` with"),
));
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!(
"\ncandidate #{}: `{}`",
i + 1,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ middle_assert_coroutine_resume_after_return = coroutine resumed after completion
middle_assert_divide_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 =
misaligned pointer dereference: address must be a multiple of {$required} but is {$found}
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_middle/src/mir/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,7 @@ impl<O> AssertKind<O> {
middle_assert_coroutine_resume_after_return
}
ResumedAfterPanic(CoroutineKind::Async(_)) => middle_assert_async_resume_after_panic,
// FIXME(gen_blocks): custom error message for `gen` blocks
ResumedAfterPanic(CoroutineKind::Gen(_)) => middle_assert_async_resume_after_panic,
ResumedAfterPanic(CoroutineKind::Gen(_)) => middle_assert_gen_resume_after_panic,
ResumedAfterPanic(CoroutineKind::Coroutine) => {
middle_assert_coroutine_resume_after_panic
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
let specialized = pat.specialize(pcx, &ctor);
for (subpat, column) in specialized.iter().zip(&mut specialized_columns) {
if subpat.is_or_pat() {
column.patterns.extend(subpat.iter_fields())
column.patterns.extend(subpat.flatten_or_pat())
} else {
column.patterns.push(subpat)
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,8 @@ parse_found_expr_would_be_stmt = expected expression, found `{$token}`
parse_function_body_equals_expr = function body cannot be `= expression;`
.suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
parse_gen_block = `gen` blocks are not yet implemented
.help = only the keyword is reserved for now
parse_gen_fn = `gen` functions are not yet implemented
.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
Expand Down
Loading

0 comments on commit 31bc7e2

Please sign in to comment.