Skip to content

Rollup of 7 pull requests #127526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 21 commits into from
Closed
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
90cbd0b
impl FusedIterator and a size hint for the error sources iter
Sky9x Jun 28, 2024
d9ed923
Use verbose style when suggesting changing `const` with `let`
estebank Jul 5, 2024
ab56dfd
Account for `let foo = expr`; to suggest `const foo: Ty = expr;`
estebank Jul 8, 2024
321eba5
Update f16/f128 FIXMEs that needed (NEG_)INFINITY
tgross35 Jul 8, 2024
ec662e7
`#[doc(alias)]`'s doc: say that ASCII spaces are allowed
ShE3py Jul 8, 2024
96a7916
Update a f16/f128 FIXME to be more accurate
tgross35 Jul 8, 2024
7097dbc
exhaustively destructure external constraints
lcnr Jul 9, 2024
e38109d
use `update_parent_goal` for lazy updates
lcnr Jul 9, 2024
fd9a925
Automatically taint when reporting errors from ItemCtxt
oli-obk Jul 5, 2024
aece064
Remove HirTyLowerer::set_tainted_by_errors, since it is now redundant
oli-obk Jul 5, 2024
dd175fe
cycle_participants to nested_goals
lcnr Jul 9, 2024
7af825f
Split out overflow handling into its own module
compiler-errors Jul 8, 2024
cd68a28
Move some stuff into the ambiguity and suggestion modules
compiler-errors Jul 8, 2024
bbbff80
Split out fulfillment error reporting a bit more
compiler-errors Jul 8, 2024
6e5f0fe
Rollup merge of #127091 - Sky9x:fused-error-sources-iter, r=dtolnay
matthiaskrgr Jul 9, 2024
2765d5c
Rollup merge of #127358 - oli-obk:taint_itemctxt, r=fmease
matthiaskrgr Jul 9, 2024
3cbf0a9
Rollup merge of #127382 - estebank:const-let, r=compiler-errors
matthiaskrgr Jul 9, 2024
16ed243
Rollup merge of #127484 - ShE3py:rustdoc-doc-alias-whitespace-doc, r=…
matthiaskrgr Jul 9, 2024
889f133
Rollup merge of #127495 - compiler-errors:more-trait-error-reworking,…
matthiaskrgr Jul 9, 2024
2db1e7a
Rollup merge of #127496 - tgross35:f16-f128-pattern-fixme, r=Nadrieril
matthiaskrgr Jul 9, 2024
705ff01
Rollup merge of #127508 - lcnr:search-graph-prep, r=compiler-errors
matthiaskrgr Jul 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 67 additions & 33 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
@@ -18,7 +18,9 @@ use rustc_ast::Recovered;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_data_structures::unord::UnordMap;
use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, E0228};
use rustc_errors::{
struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, StashKey, E0228,
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, walk_generics, Visitor};
@@ -161,7 +163,7 @@ pub struct CollectItemTypesVisitor<'tcx> {
/// and suggest adding type parameters in the appropriate place, taking into consideration any and
/// all already existing generic type parameters to avoid suggesting a name that is already in use.
pub(crate) fn placeholder_type_error<'tcx>(
tcx: TyCtxt<'tcx>,
cx: &dyn HirTyLowerer<'tcx>,
generics: Option<&hir::Generics<'_>>,
placeholder_types: Vec<Span>,
suggest: bool,
@@ -172,21 +174,21 @@ pub(crate) fn placeholder_type_error<'tcx>(
return;
}

placeholder_type_error_diag(tcx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
placeholder_type_error_diag(cx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
.emit();
}

pub(crate) fn placeholder_type_error_diag<'tcx>(
tcx: TyCtxt<'tcx>,
pub(crate) fn placeholder_type_error_diag<'cx, 'tcx>(
cx: &'cx dyn HirTyLowerer<'tcx>,
generics: Option<&hir::Generics<'_>>,
placeholder_types: Vec<Span>,
additional_spans: Vec<Span>,
suggest: bool,
hir_ty: Option<&hir::Ty<'_>>,
kind: &'static str,
) -> Diag<'tcx> {
) -> Diag<'cx> {
if placeholder_types.is_empty() {
return bad_placeholder(tcx, additional_spans, kind);
return bad_placeholder(cx, additional_spans, kind);
}

let params = generics.map(|g| g.params).unwrap_or_default();
@@ -210,7 +212,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
}

let mut err =
bad_placeholder(tcx, placeholder_types.into_iter().chain(additional_spans).collect(), kind);
bad_placeholder(cx, placeholder_types.into_iter().chain(additional_spans).collect(), kind);

// Suggest, but only if it is not a function in const or static
if suggest {
@@ -224,7 +226,7 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(

// Check if parent is const or static
is_const_or_static = matches!(
tcx.parent_hir_node(hir_ty.hir_id),
cx.tcx().parent_hir_node(hir_ty.hir_id),
Node::Item(&hir::Item {
kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
..
@@ -267,7 +269,16 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_item(item);

placeholder_type_error(tcx, Some(generics), visitor.0, suggest, None, item.kind.descr());
let icx = ItemCtxt::new(tcx, item.owner_id.def_id);

placeholder_type_error(
icx.lowerer(),
Some(generics),
visitor.0,
suggest,
None,
item.kind.descr(),
);
}

impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
@@ -329,15 +340,15 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
///////////////////////////////////////////////////////////////////////////
// Utility types and common code for the above passes.

fn bad_placeholder<'tcx>(
tcx: TyCtxt<'tcx>,
fn bad_placeholder<'cx, 'tcx>(
cx: &'cx dyn HirTyLowerer<'tcx>,
mut spans: Vec<Span>,
kind: &'static str,
) -> Diag<'tcx> {
) -> Diag<'cx> {
let kind = if kind.ends_with('s') { format!("{kind}es") } else { format!("{kind}s") };

spans.sort();
tcx.dcx().create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind })
cx.dcx().create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind })
}

impl<'tcx> ItemCtxt<'tcx> {
@@ -370,21 +381,24 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
self.tcx
}

fn dcx(&self) -> DiagCtxtHandle<'_> {
self.tcx.dcx().taintable_handle(&self.tainted_by_errors)
}

fn item_def_id(&self) -> LocalDefId {
self.item_def_id
}

fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
if let RegionInferReason::BorrowedObjectLifetimeDefault = reason {
let e = struct_span_code_err!(
self.tcx().dcx(),
self.dcx(),
span,
E0228,
"the lifetime bound for this object type cannot be deduced \
from context; please supply an explicit bound"
)
.emit();
self.set_tainted_by_errors(e);
ty::Region::new_error(self.tcx(), e)
} else {
// This indicates an illegal lifetime in a non-assoc-trait position
@@ -509,10 +523,6 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
None
}

fn set_tainted_by_errors(&self, err: ErrorGuaranteed) {
self.tainted_by_errors.set(Some(err));
}

fn lower_fn_sig(
&self,
decl: &hir::FnDecl<'tcx>,
@@ -570,7 +580,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
// `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.

let mut diag = crate::collect::placeholder_type_error_diag(
tcx,
self,
generics,
visitor.0,
infer_replacements.iter().map(|(s, _)| *s).collect(),
@@ -590,7 +600,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
);
}

self.set_tainted_by_errors(diag.emit());
diag.emit();
}

(input_tys, output_ty)
@@ -639,6 +649,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
let it = tcx.hir().item(item_id);
debug!(item = %it.ident, id = %it.hir_id());
let def_id = item_id.owner_id.def_id;
let icx = ItemCtxt::new(tcx, def_id);

match &it.kind {
// These don't define types.
@@ -663,7 +674,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_foreign_item(item);
placeholder_type_error(
tcx,
icx.lowerer(),
None,
visitor.0,
false,
@@ -742,7 +753,14 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
if !ty.is_suggestable_infer_ty() {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_item(it);
placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
placeholder_type_error(
icx.lowerer(),
None,
visitor.0,
false,
None,
it.kind.descr(),
);
}
}

@@ -760,6 +778,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
let trait_item = tcx.hir().trait_item(trait_item_id);
let def_id = trait_item_id.owner_id;
tcx.ensure().generics_of(def_id);
let icx = ItemCtxt::new(tcx, def_id.def_id);

match trait_item.kind {
hir::TraitItemKind::Fn(..) => {
@@ -776,7 +795,14 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
// Account for `const C: _;`.
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant");
placeholder_type_error(
icx.lowerer(),
None,
visitor.0,
false,
None,
"associated constant",
);
}
}

@@ -787,7 +813,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
// Account for `type T = _;`.
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);
placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type");
}

hir::TraitItemKind::Type(_, None) => {
@@ -798,7 +824,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_trait_item(trait_item);

placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type");
}
};

@@ -811,6 +837,7 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
let impl_item = tcx.hir().impl_item(impl_item_id);
let icx = ItemCtxt::new(tcx, def_id.def_id);
match impl_item.kind {
hir::ImplItemKind::Fn(..) => {
tcx.ensure().codegen_fn_attrs(def_id);
@@ -821,14 +848,21 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_impl_item(impl_item);

placeholder_type_error(tcx, None, visitor.0, false, None, "associated type");
placeholder_type_error(icx.lowerer(), None, visitor.0, false, None, "associated type");
}
hir::ImplItemKind::Const(ty, _) => {
// Account for `const T: _ = ..;`
if !ty.is_suggestable_infer_ty() {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_impl_item(impl_item);
placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant");
placeholder_type_error(
icx.lowerer(),
None,
visitor.0,
false,
None,
"associated constant",
);
}
}
}
@@ -1385,7 +1419,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
..
})
| Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
}

ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
@@ -1402,7 +1436,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
None,
)
} else {
infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx)
infer_return_ty_for_fn_sig(sig, generics, def_id, &icx)
}
}

@@ -1455,12 +1489,12 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
}

fn infer_return_ty_for_fn_sig<'tcx>(
tcx: TyCtxt<'tcx>,
sig: &hir::FnSig<'tcx>,
generics: &hir::Generics<'_>,
def_id: LocalDefId,
icx: &ItemCtxt<'tcx>,
) -> ty::PolyFnSig<'tcx> {
let tcx = icx.tcx;
let hir_id = tcx.local_def_id_to_hir_id(def_id);

match sig.decl.output.get_infer_ret_ty() {
@@ -1492,7 +1526,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_ty(ty);

let mut diag = bad_placeholder(tcx, visitor.0, "return type");
let mut diag = bad_placeholder(icx.lowerer(), visitor.0, "return type");
let ret_ty = fn_sig.output();
// Don't leak types into signatures unless they're nameable!
// For example, if a function returns itself, we don't want that
27 changes: 18 additions & 9 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};

use crate::errors::TypeofReservedKeywordUsed;
use crate::hir_ty_lowering::HirTyLowerer;

use super::bad_placeholder;
use super::ItemCtxt;
@@ -357,7 +358,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
.and_then(|body_id| {
ty.is_suggestable_infer_ty().then(|| {
infer_placeholder_type(
tcx,
icx.lowerer(),
def_id,
body_id,
ty.span,
@@ -381,7 +382,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
ImplItemKind::Const(ty, body_id) => {
if ty.is_suggestable_infer_ty() {
infer_placeholder_type(
tcx,
icx.lowerer(),
def_id,
body_id,
ty.span,
@@ -405,7 +406,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
ItemKind::Static(ty, .., body_id) => {
if ty.is_suggestable_infer_ty() {
infer_placeholder_type(
tcx,
icx.lowerer(),
def_id,
body_id,
ty.span,
@@ -418,7 +419,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
}
ItemKind::Const(ty, _, body_id) => {
if ty.is_suggestable_infer_ty() {
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
infer_placeholder_type(
icx.lowerer(),
def_id,
body_id,
ty.span,
item.ident,
"constant",
)
} else {
icx.lower_ty(ty)
}
@@ -559,21 +567,22 @@ pub(super) fn type_of_opaque(
}
}

fn infer_placeholder_type<'a>(
tcx: TyCtxt<'a>,
fn infer_placeholder_type<'tcx>(
cx: &dyn HirTyLowerer<'tcx>,
def_id: LocalDefId,
body_id: hir::BodyId,
span: Span,
item_ident: Ident,
kind: &'static str,
) -> Ty<'a> {
) -> Ty<'tcx> {
let tcx = cx.tcx();
let ty = tcx.diagnostic_only_typeck(def_id).node_type(body_id.hir_id);

// If this came from a free `const` or `static mut?` item,
// then the user may have written e.g. `const A = 42;`.
// In this case, the parser has stashed a diagnostic for
// us to improve in typeck so we do that now.
let guar = tcx
let guar = cx
.dcx()
.try_steal_modify_and_emit_err(span, StashKey::ItemNoType, |err| {
if !ty.references_error() {
@@ -602,7 +611,7 @@ fn infer_placeholder_type<'a>(
}
})
.unwrap_or_else(|| {
let mut diag = bad_placeholder(tcx, vec![span], kind);
let mut diag = bad_placeholder(cx, vec![span], kind);

if !ty.references_error() {
if let Some(ty) = ty.make_suggestable(tcx, false, None) {
39 changes: 20 additions & 19 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
Original file line number Diff line number Diff line change
@@ -76,7 +76,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}

if unbounds.len() > 1 {
tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds {
self.dcx().emit_err(errors::MultipleRelaxedDefaultBounds {
spans: unbounds.iter().map(|ptr| ptr.span).collect(),
});
}
@@ -90,7 +90,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
continue;
}
// There was a `?Trait` bound, but it was not `?Sized`; warn.
tcx.dcx().span_warn(
self.dcx().span_warn(
unbound.span,
"relaxing a default bound only does something for `?Sized`; \
all other traits are not bound by default",
@@ -310,7 +310,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
duplicates
.entry(assoc_item.def_id)
.and_modify(|prev_span| {
tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
span: constraint.span,
prev_span: *prev_span,
item_name: constraint.ident,
@@ -338,7 +338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.into(),
ty::GenericParamDefKind::Type { .. } => {
let guar = *emitted_bad_param_err.get_or_insert_with(|| {
tcx.dcx().emit_err(
self.dcx().emit_err(
crate::errors::ReturnTypeNotationIllegalParam::Type {
span: path_span,
param_span: tcx.def_span(param.def_id),
@@ -349,7 +349,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
ty::GenericParamDefKind::Const { .. } => {
let guar = *emitted_bad_param_err.get_or_insert_with(|| {
tcx.dcx().emit_err(
self.dcx().emit_err(
crate::errors::ReturnTypeNotationIllegalParam::Const {
span: path_span,
param_span: tcx.def_span(param.def_id),
@@ -371,7 +371,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
{
alias_ty.into()
} else {
return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
span: constraint.span,
ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
fn_span: tcx.hir().span_if_local(assoc_item.def_id),
@@ -417,7 +417,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let ty = alias_term
.map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
let ty =
check_assoc_const_binding_type(tcx, constraint.ident, ty, constraint.hir_id);
check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id);
tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
}

@@ -426,7 +426,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

match constraint.kind {
hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
span: constraint.span,
}));
}
@@ -462,7 +462,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
late_bound_in_term,
|br_name| {
struct_span_code_err!(
tcx.dcx(),
self.dcx(),
constraint.span,
E0582,
"binding for associated type `{}` references {}, \
@@ -519,7 +519,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
///
/// [^1]: <https://github.com/rust-lang/project-const-generics/issues/28>.
fn check_assoc_const_binding_type<'tcx>(
tcx: TyCtxt<'tcx>,
cx: &dyn HirTyLowerer<'tcx>,
assoc_const: Ident,
ty: ty::Binder<'tcx, Ty<'tcx>>,
hir_id: hir::HirId,
@@ -536,13 +536,14 @@ fn check_assoc_const_binding_type<'tcx>(
}

let mut collector = GenericParamAndBoundVarCollector {
tcx,
cx,
params: Default::default(),
vars: Default::default(),
depth: ty::INNERMOST,
};
let mut guar = ty.visit_with(&mut collector).break_value();

let tcx = cx.tcx();
let ty_note = ty
.make_suggestable(tcx, false, None)
.map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty });
@@ -556,7 +557,7 @@ fn check_assoc_const_binding_type<'tcx>(
for index in collector.params {
let param = generics.param_at(index as _, tcx);
let is_self_param = param.name == rustc_span::symbol::kw::SelfUpper;
guar.get_or_insert(tcx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding {
guar.get_or_insert(cx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding {
span: assoc_const.span,
assoc_const,
param_name: param.name,
@@ -574,7 +575,7 @@ fn check_assoc_const_binding_type<'tcx>(
}));
}
for (var_def_id, var_name) in collector.vars {
guar.get_or_insert(tcx.dcx().emit_err(
guar.get_or_insert(cx.dcx().emit_err(
crate::errors::EscapingBoundVarInTyOfAssocConstBinding {
span: assoc_const.span,
assoc_const,
@@ -590,14 +591,14 @@ fn check_assoc_const_binding_type<'tcx>(
Ty::new_error(tcx, guar)
}

struct GenericParamAndBoundVarCollector<'tcx> {
tcx: TyCtxt<'tcx>,
struct GenericParamAndBoundVarCollector<'a, 'tcx> {
cx: &'a dyn HirTyLowerer<'tcx>,
params: FxIndexSet<u32>,
vars: FxIndexSet<(DefId, Symbol)>,
depth: ty::DebruijnIndex,
}

impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx> {
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 'tcx> {
type Result = ControlFlow<ErrorGuaranteed>;

fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
@@ -620,7 +621,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx>
ty::BoundTyKind::Param(def_id, name) => (def_id, name),
ty::BoundTyKind::Anon => {
let reported = self
.tcx
.cx
.dcx()
.delayed_bug(format!("unexpected anon bound ty: {:?}", bt.var));
return ControlFlow::Break(reported);
@@ -643,7 +644,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx>
ty::BrNamed(def_id, name) => (def_id, name),
ty::BrAnon | ty::BrEnv => {
let guar = self
.tcx
.cx
.dcx()
.delayed_bug(format!("unexpected bound region kind: {:?}", br.kind));
return ControlFlow::Break(guar);
@@ -661,7 +662,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx>
self.params.insert(param.index);
}
ty::ConstKind::Bound(db, ty::BoundVar { .. }) if db >= self.depth => {
let guar = self.tcx.dcx().delayed_bug("unexpected escaping late-bound const var");
let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var");
return ControlFlow::Break(guar);
}
_ if ct.has_param() || ct.has_bound_vars() => return ct.super_visit_with(self),
82 changes: 34 additions & 48 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
Original file line number Diff line number Diff line change
@@ -46,7 +46,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
return;
}

self.tcx().dcx().emit_err(MissingTypeParams {
self.dcx().emit_err(MissingTypeParams {
span,
def_span: self.tcx().def_span(def_id),
span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(),
@@ -109,7 +109,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

if is_impl {
let trait_name = self.tcx().def_path_str(trait_def_id);
self.tcx().dcx().emit_err(ManualImplementation { span, trait_name });
self.dcx().emit_err(ManualImplementation { span, trait_name });
}
}

@@ -156,7 +156,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

if is_dummy {
err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span });
return tcx.dcx().emit_err(err);
return self.dcx().emit_err(err);
}

let all_candidate_names: Vec<_> = all_candidates()
@@ -174,7 +174,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
assoc_kind: assoc_kind_str,
suggested_name,
});
return tcx.dcx().emit_err(err);
return self.dcx().emit_err(err);
}

// If we didn't find a good item in the supertraits (or couldn't get
@@ -239,10 +239,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
assoc_kind: assoc_kind_str,
suggested_name,
});
return tcx.dcx().emit_err(err);
return self.dcx().emit_err(err);
}

let mut err = tcx.dcx().create_err(err);
let mut err = self.dcx().create_err(err);
if suggest_constraining_type_param(
tcx,
generics,
@@ -264,7 +264,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
return err.emit();
}
return tcx.dcx().emit_err(err);
return self.dcx().emit_err(err);
}
}

@@ -291,7 +291,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_name.span });
}

tcx.dcx().emit_err(err)
self.dcx().emit_err(err)
}

fn complain_about_assoc_kind_mismatch(
@@ -347,7 +347,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
(ident.span, None, assoc_kind, assoc_item.kind)
};

tcx.dcx().emit_err(errors::AssocKindMismatch {
self.dcx().emit_err(errors::AssocKindMismatch {
span,
expected: super::assoc_kind_str(expected),
got: super::assoc_kind_str(got),
@@ -366,8 +366,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
traits: &[String],
name: Symbol,
) -> ErrorGuaranteed {
let mut err =
struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type");
let mut err = struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type");
if self
.tcx()
.resolutions(())
@@ -463,9 +462,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
}
let reported = err.emit();
self.set_tainted_by_errors(reported);
reported
err.emit()
}

pub(crate) fn complain_about_ambiguous_inherent_assoc_ty(
@@ -475,16 +472,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span: Span,
) -> ErrorGuaranteed {
let mut err = struct_span_code_err!(
self.tcx().dcx(),
self.dcx(),
name.span,
E0034,
"multiple applicable items in scope"
);
err.span_label(name.span, format!("multiple `{name}` found"));
self.note_ambiguous_inherent_assoc_ty(&mut err, candidates, span);
let reported = err.emit();
self.set_tainted_by_errors(reported);
reported
err.emit()
}

// FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate.
@@ -576,7 +571,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};

let mut err = struct_span_code_err!(
tcx.dcx(),
self.dcx(),
name.span,
E0220,
"associated type `{name}` not found for `{self_ty}` in the current scope"
@@ -662,7 +657,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
bounds.sort();
bounds.dedup();

let mut err = tcx.dcx().struct_span_err(
let mut err = self.dcx().struct_span_err(
name.span,
format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
);
@@ -829,7 +824,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

trait_bound_spans.sort();
let mut err = struct_span_code_err!(
tcx.dcx(),
self.dcx(),
trait_bound_spans,
E0191,
"the value of the associated type{} {} must be specified",
@@ -974,7 +969,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}

self.set_tainted_by_errors(err.emit());
err.emit();
}

/// On ambiguous associated type, look for an associated function whose name matches the
@@ -1011,17 +1006,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.filter_by_name_unhygienic(Symbol::intern(&name))
.next()
{
let reported =
struct_span_code_err!(tcx.dcx(), span, E0223, "ambiguous associated type")
.with_span_suggestion_verbose(
ident2.span.to(ident3.span),
format!("there is an associated function with a similar name: `{name}`"),
name,
Applicability::MaybeIncorrect,
)
.emit();
self.set_tainted_by_errors(reported);
Err(reported)
Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
.with_span_suggestion_verbose(
ident2.span.to(ident3.span),
format!("there is an associated function with a similar name: `{name}`"),
name,
Applicability::MaybeIncorrect,
)
.emit())
} else {
Ok(())
}
@@ -1120,7 +1112,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let last_span = *arg_spans.last().unwrap();
let span: MultiSpan = arg_spans.into();
let mut err = struct_span_code_err!(
self.tcx().dcx(),
self.dcx(),
span,
E0109,
"{kind} arguments are not allowed on {this_type}",
@@ -1130,20 +1122,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
err.span_label(span, format!("not allowed on {what}"));
}
generics_args_err_extend(self.tcx(), segments, &mut err, err_extend);
let reported = err.emit();
self.set_tainted_by_errors(reported);
reported
err.emit()
}

pub fn report_trait_object_addition_traits_error(
&self,
regular_traits: &Vec<TraitAliasExpansionInfo<'_>>,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let first_trait = &regular_traits[0];
let additional_trait = &regular_traits[1];
let mut err = struct_span_code_err!(
tcx.dcx(),
self.dcx(),
additional_trait.bottom().1,
E0225,
"only auto traits can be used as additional traits in a trait object"
@@ -1169,9 +1158,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
for more information on them, visit \
<https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
);
let reported = err.emit();
self.set_tainted_by_errors(reported);
reported
err.emit()
}

pub fn report_trait_object_with_no_traits_error(
@@ -1185,20 +1172,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.map(|&(trait_ref, _)| trait_ref.def_id())
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
.map(|trait_ref| tcx.def_span(trait_ref));
let reported =
tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
self.set_tainted_by_errors(reported);
reported

self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span })
}
}

/// Emit an error for the given associated item constraint.
pub fn prohibit_assoc_item_constraint(
tcx: TyCtxt<'_>,
cx: &dyn HirTyLowerer<'_>,
constraint: &hir::AssocItemConstraint<'_>,
segment: Option<(DefId, &hir::PathSegment<'_>, Span)>,
) -> ErrorGuaranteed {
let mut err = tcx.dcx().create_err(AssocItemConstraintsNotAllowedHere {
let tcx = cx.tcx();
let mut err = cx.dcx().create_err(AssocItemConstraintsNotAllowedHere {
span: constraint.span,
fn_trait_expansion: if let Some((_, segment, span)) = segment
&& segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
42 changes: 22 additions & 20 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::IsMethodCall;
use super::{HirTyLowerer, IsMethodCall};
use crate::errors::wrong_number_of_generic_args::{GenericArgsInfo, WrongNumberOfGenericArgs};
use crate::hir_ty_lowering::{
errors::prohibit_assoc_item_constraint, ExplicitLateBound, GenericArgCountMismatch,
@@ -13,7 +13,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
use rustc_middle::ty::{
self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt,
self, GenericArgsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty,
};
use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
use rustc_span::symbol::{kw, sym};
@@ -22,15 +22,16 @@ use smallvec::SmallVec;
/// Report an error that a generic argument did not match the generic parameter that was
/// expected.
fn generic_arg_mismatch_err(
tcx: TyCtxt<'_>,
cx: &dyn HirTyLowerer<'_>,
arg: &GenericArg<'_>,
param: &GenericParamDef,
possible_ordering_error: bool,
help: Option<String>,
) -> ErrorGuaranteed {
let tcx = cx.tcx();
let sess = tcx.sess;
let mut err = struct_span_code_err!(
tcx.dcx(),
cx.dcx(),
arg.span(),
E0747,
"{} provided when a {} was expected",
@@ -171,14 +172,15 @@ fn generic_arg_mismatch_err(
/// - `inferred_kind`: if no parameter was provided, and inference
/// is enabled, then creates a suitable inference variable.
pub fn lower_generic_args<'tcx: 'a, 'a>(
tcx: TyCtxt<'tcx>,
cx: &dyn HirTyLowerer<'tcx>,
def_id: DefId,
parent_args: &[ty::GenericArg<'tcx>],
has_self: bool,
self_ty: Option<Ty<'tcx>>,
arg_count: &GenericArgCountResult,
ctx: &mut impl GenericArgsLowerer<'a, 'tcx>,
) -> GenericArgsRef<'tcx> {
let tcx = cx.tcx();
// Collect the segments of the path; we need to instantiate arguments
// for parameters throughout the entire path (wherever there are
// generic parameters).
@@ -326,7 +328,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
param_types_present.dedup();

generic_arg_mismatch_err(
tcx,
cx,
arg,
param,
!args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()),
@@ -381,7 +383,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
assert_eq!(kind, "lifetime");
let (provided_arg, param) =
force_infer_lt.expect("lifetimes ought to have been inferred");
generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
generic_arg_mismatch_err(cx, provided_arg, param, false, None);
}

break;
@@ -405,7 +407,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>(
/// Checks that the correct number of generic arguments have been provided.
/// Used specifically for function calls.
pub fn check_generic_arg_count_for_call(
tcx: TyCtxt<'_>,
cx: &dyn HirTyLowerer<'_>,
def_id: DefId,
generics: &ty::Generics,
seg: &hir::PathSegment<'_>,
@@ -416,14 +418,14 @@ pub fn check_generic_arg_count_for_call(
IsMethodCall::No => GenericArgPosition::Value,
};
let has_self = generics.parent.is_none() && generics.has_self;
check_generic_arg_count(tcx, def_id, seg, generics, gen_pos, has_self)
check_generic_arg_count(cx, def_id, seg, generics, gen_pos, has_self)
}

/// Checks that the correct number of generic arguments have been provided.
/// This is used both for datatypes and function calls.
#[instrument(skip(tcx, gen_pos), level = "debug")]
#[instrument(skip(cx, gen_pos), level = "debug")]
pub(crate) fn check_generic_arg_count(
tcx: TyCtxt<'_>,
cx: &dyn HirTyLowerer<'_>,
def_id: DefId,
seg: &hir::PathSegment<'_>,
gen_params: &ty::Generics,
@@ -456,11 +458,11 @@ pub(crate) fn check_generic_arg_count(
if gen_pos != GenericArgPosition::Type
&& let Some(c) = gen_args.constraints.first()
{
prohibit_assoc_item_constraint(tcx, c, None);
prohibit_assoc_item_constraint(cx, c, None);
}

let explicit_late_bound =
prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);
prohibit_explicit_late_bound_lifetimes(cx, gen_params, gen_args, gen_pos);

let mut invalid_args = vec![];

@@ -486,8 +488,8 @@ pub(crate) fn check_generic_arg_count(
GenericArgsInfo::MissingLifetimes { num_missing_args }
};

let reported = tcx.dcx().emit_err(WrongNumberOfGenericArgs::new(
tcx,
let reported = cx.dcx().emit_err(WrongNumberOfGenericArgs::new(
cx.tcx(),
gen_args_info,
seg,
gen_params,
@@ -571,9 +573,9 @@ pub(crate) fn check_generic_arg_count(
debug!(?gen_args_info);

let reported = gen_args.has_err().unwrap_or_else(|| {
tcx.dcx()
cx.dcx()
.create_err(WrongNumberOfGenericArgs::new(
tcx,
cx.tcx(),
gen_args_info,
seg,
gen_params,
@@ -621,7 +623,7 @@ pub(crate) fn check_generic_arg_count(
/// Prohibits explicit lifetime arguments if late-bound lifetime parameters
/// are present. This is used both for datatypes and function calls.
pub(crate) fn prohibit_explicit_late_bound_lifetimes(
tcx: TyCtxt<'_>,
cx: &dyn HirTyLowerer<'_>,
def: &ty::Generics,
args: &hir::GenericArgs<'_>,
position: GenericArgPosition,
@@ -642,13 +644,13 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
if position == GenericArgPosition::Value
&& args.num_lifetime_params() != param_counts.lifetimes
{
struct_span_code_err!(tcx.dcx(), span, E0794, "{}", msg)
struct_span_code_err!(cx.dcx(), span, E0794, "{}", msg)
.with_span_note(span_late, note)
.emit();
} else {
let mut multispan = MultiSpan::from_span(span);
multispan.push_span_label(span_late, note);
tcx.node_span_lint(
cx.tcx().node_span_lint(
LATE_BOUND_LIFETIME_ARGUMENTS,
args.args[0].hir_id(),
multispan,
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let msg = "trait objects must include the `dyn` keyword";
let label = "add `dyn` keyword before this trait";
let mut diag =
rustc_errors::struct_span_code_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg);
if self_ty.span.can_be_used_for_suggestions()
&& !self.maybe_suggest_impl_trait(self_ty, &mut diag)
{
77 changes: 29 additions & 48 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
@@ -28,7 +28,8 @@ use crate::require_c_abi_if_c_variadic;
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::{
codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
codes::*, struct_span_code_err, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed,
FatalError,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@@ -102,6 +103,8 @@ pub enum RegionInferReason<'a> {
pub trait HirTyLowerer<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx>;

fn dcx(&self) -> DiagCtxtHandle<'_>;

/// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered.
fn item_def_id(&self) -> LocalDefId;

@@ -177,12 +180,6 @@ pub trait HirTyLowerer<'tcx> {
/// The inference context of the lowering context if applicable.
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;

/// Taint the context with errors.
///
/// Invoke this when you encounter an error from some prior pass like name resolution.
/// This is used to help suppress derived errors typeck might otherwise report.
fn set_tainted_by_errors(&self, e: ErrorGuaranteed);

/// Convenience method for coercing the lowering context into a trait object type.
///
/// Most lowering routines are defined on the trait object type directly
@@ -323,7 +320,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
ty::BoundConstness::NotConst,
);
if let Some(c) = item_segment.args().constraints.first() {
prohibit_assoc_item_constraint(self.tcx(), c, Some((def_id, item_segment, span)));
prohibit_assoc_item_constraint(self, c, Some((def_id, item_segment, span)));
}
args
}
@@ -394,18 +391,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}

let mut arg_count = check_generic_arg_count(
tcx,
self,
def_id,
segment,
generics,
GenericArgPosition::Type,
self_ty.is_some(),
);

if let Err(err) = &arg_count.correct {
self.set_tainted_by_errors(err.reported);
}

// Skip processing if type has no generic parameters.
// Traits always have `Self` as a generic parameter, which means they will not return early
// here and so associated item constraints will be handled regardless of whether there are
@@ -562,11 +555,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&& generics.has_self
&& !tcx.is_const_trait(def_id)
{
let reported = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
let reported = self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
span,
modifier: constness.as_str(),
});
self.set_tainted_by_errors(reported);
arg_count.correct = Err(GenericArgCountMismatch { reported, invalid_args: vec![] });
}

@@ -579,7 +571,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
incorrect_args: &arg_count.correct,
};
let args = lower_generic_args(
tcx,
self,
def_id,
parent_args,
self_ty.is_some(),
@@ -609,7 +601,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
ty::BoundConstness::NotConst,
);
if let Some(c) = item_segment.args().constraints.first() {
prohibit_assoc_item_constraint(self.tcx(), c, Some((item_def_id, item_segment, span)));
prohibit_assoc_item_constraint(self, c, Some((item_def_id, item_segment, span)));
}
args
}
@@ -715,7 +707,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// would not be well-formed!
if polarity != ty::PredicatePolarity::Positive {
assert!(
self.tcx().dcx().has_errors().is_some(),
self.dcx().has_errors().is_some(),
"negative trait bounds should not have assoc item constraints",
);
continue;
@@ -761,11 +753,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
constness,
);
if let Some(c) = trait_segment.args().constraints.first() {
prohibit_assoc_item_constraint(
self.tcx(),
c,
Some((trait_def_id, trait_segment, span)),
);
prohibit_assoc_item_constraint(self, c, Some((trait_def_id, trait_segment, span)));
}
ty::TraitRef::new_from_args(self.tcx(), trait_def_id, generic_args)
}
@@ -877,7 +865,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span,
constraint,
);
self.set_tainted_by_errors(reported);
return Err(reported);
};
debug!(?bound);
@@ -887,7 +874,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

let assoc_kind_str = assoc_kind_str(assoc_kind);
let ty_param_name = &ty_param_name.to_string();
let mut err = tcx.dcx().create_err(crate::errors::AmbiguousAssocItem {
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
span,
assoc_kind: assoc_kind_str,
assoc_name,
@@ -960,7 +947,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
));
}
let reported = err.emit();
self.set_tainted_by_errors(reported);
if !where_bounds.is_empty() {
return Err(reported);
}
@@ -1059,7 +1045,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// trait reference.
let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
// A cycle error occurred, most likely.
tcx.dcx().span_bug(span, "expected cycle error");
self.dcx().span_bug(span, "expected cycle error");
};

self.probe_single_bound_for_assoc_item(
@@ -1089,10 +1075,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let reported = if variant_resolution.is_some() {
// Variant in type position
let msg = format!("expected type, found variant `{assoc_ident}`");
tcx.dcx().span_err(span, msg)
self.dcx().span_err(span, msg)
} else if qself_ty.is_enum() {
let mut err = struct_span_code_err!(
tcx.dcx(),
self.dcx(),
assoc_ident.span,
E0599,
"no variant named `{}` found for enum `{}`",
@@ -1133,7 +1119,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
} else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
// `<impl Trait as OtherTrait>::Assoc` makes no sense.
struct_span_code_err!(
tcx.dcx(),
self.dcx(),
tcx.def_span(alias_ty.def_id),
E0667,
"`impl Trait` is not allowed in path parameters"
@@ -1153,7 +1139,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
assoc_ident.name,
)
};
self.set_tainted_by_errors(reported);
return Err(reported);
}
};
@@ -1404,13 +1389,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx();

if !tcx.visibility(item_def_id).is_accessible_from(scope, tcx) {
let reported = tcx.dcx().emit_err(crate::errors::AssocItemIsPrivate {
self.dcx().emit_err(crate::errors::AssocItemIsPrivate {
span,
kind: tcx.def_descr(item_def_id),
name: ident,
defined_here_label: tcx.def_span(item_def_id),
});
self.set_tainted_by_errors(reported);
}

tcx.check_stability(item_def_id, Some(block), span, None);
@@ -1564,7 +1548,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
for segment in segments {
// Only emit the first error to avoid overloading the user with error messages.
if let Some(c) = segment.args().constraints.first() {
return Err(prohibit_assoc_item_constraint(self.tcx(), c, None));
return Err(prohibit_assoc_item_constraint(self, c, None));
}
}

@@ -1824,7 +1808,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// `AlwaysApplicable` impl needs a `T: ?Sized` bound for
// this to compile if we were to normalize here.
if forbid_generic && ty.has_param() {
let mut err = tcx.dcx().struct_span_err(
let mut err = self.dcx().struct_span_err(
path.span,
"generic `Self` types are currently not permitted in anonymous constants",
);
@@ -1836,7 +1820,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
err.span_note(impl_.self_ty.span, "not a concrete type");
}
let reported = err.emit();
self.set_tainted_by_errors(reported);
Ty::new_error(tcx, reported)
} else {
ty
@@ -1877,7 +1860,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.tcx()
.dcx()
.span_delayed_bug(path.span, "path with `Res::Err` but no error emitted");
self.set_tainted_by_errors(e);
Ty::new_error(self.tcx(), e)
}
Res::Def(..) => {
@@ -1888,7 +1870,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
);
Ty::new_error(
self.tcx(),
self.tcx().dcx().span_delayed_bug(span, "incorrect resolution for `Self`"),
self.dcx().span_delayed_bug(span, "incorrect resolution for `Self`"),
)
}
_ => span_bug!(span, "unexpected resolution: {:?}", path.res),
@@ -1961,7 +1943,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let sig_span = self.tcx().def_span(sig_id);
let mut try_emit = |descr| {
if emit {
self.tcx().dcx().emit_err(crate::errors::NotSupportedDelegation {
self.dcx().emit_err(crate::errors::NotSupportedDelegation {
span,
descr,
callee_span: sig_span,
@@ -2011,8 +1993,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
) -> Ty<'tcx> {
if self.check_delegation_constraints(sig_id, span, idx == hir::InferDelegationKind::Output)
{
let e = self.tcx().dcx().span_delayed_bug(span, "not supported delegation case");
self.set_tainted_by_errors(e);
let e = self.dcx().span_delayed_bug(span, "not supported delegation case");
return Ty::new_error(self.tcx(), e);
};
let sig = self.tcx().fn_sig(sig_id);
@@ -2177,7 +2158,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let ty = self.lower_ty(ty);
let pat_ty = match pat.kind {
hir::PatKind::Wild => {
let err = tcx.dcx().emit_err(WildPatTy { span: pat.span });
let err = self.dcx().emit_err(WildPatTy { span: pat.span });
Ty::new_error(tcx, err)
}
hir::PatKind::Range(start, end, include_end) => {
@@ -2357,7 +2338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| {
struct_span_code_err!(
tcx.dcx(),
self.dcx(),
decl.output.span(),
E0581,
"return type references {}, which is not constrained by the fn input types",
@@ -2408,11 +2389,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}

#[instrument(level = "trace", skip(self, generate_err))]
fn validate_late_bound_regions(
&self,
fn validate_late_bound_regions<'cx>(
&'cx self,
constrained_regions: FxHashSet<ty::BoundRegionKind>,
referenced_regions: FxHashSet<ty::BoundRegionKind>,
generate_err: impl Fn(&str) -> Diag<'tcx>,
generate_err: impl Fn(&str) -> Diag<'cx>,
) {
for br in referenced_regions.difference(&constrained_regions) {
let br_name = match *br {
@@ -2437,7 +2418,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
err.note("consider introducing a named lifetime parameter");
}

self.set_tainted_by_errors(err.emit());
err.emit();
}
}

@@ -2478,7 +2459,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// error.
let r = derived_region_bounds[0];
if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
self.set_tainted_by_errors(tcx.dcx().emit_err(AmbiguousLifetimeBound { span }));
self.dcx().emit_err(AmbiguousLifetimeBound { span });
}
Some(r)
}
Original file line number Diff line number Diff line change
@@ -236,7 +236,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Ty::new_misc_error(tcx).into()
} else if arg.walk().any(|arg| arg == dummy_self.into()) {
references_self = true;
let guar = tcx.dcx().span_delayed_bug(
let guar = self.dcx().span_delayed_bug(
span,
"trait object trait bounds reference `Self`",
);
@@ -262,8 +262,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {

if references_self {
let def_id = i.bottom().0.def_id();
let reported = struct_span_code_err!(
tcx.dcx(),
struct_span_code_err!(
self.dcx(),
i.bottom().1,
E0038,
"the {} `{}` cannot be made into an object",
@@ -275,7 +275,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.error_msg(),
)
.emit();
self.set_tainted_by_errors(reported);
}

ty::ExistentialTraitRef { def_id: trait_ref.def_id, args }
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ use rustc_span::symbol::sym;
use rustc_span::{BytePos, DesugaringKind, Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt;
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _;
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtSelectionErrExt as _;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
@@ -1139,7 +1139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// parameter's value explicitly, so we have to do some error-
// checking here.
let arg_count =
check_generic_arg_count_for_call(tcx, def_id, generics, seg, IsMethodCall::No);
check_generic_arg_count_for_call(self, def_id, generics, seg, IsMethodCall::No);

if let ExplicitLateBound::Yes = arg_count.explicit_late_bound {
explicit_late_bound = ExplicitLateBound::Yes;
@@ -1375,7 +1375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let args_raw = self_ctor_args.unwrap_or_else(|| {
lower_generic_args(
tcx,
self,
def_id,
&[],
has_self,
10 changes: 5 additions & 5 deletions compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ mod checks;
mod inspect_obligations;
mod suggestions;

use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed};
use rustc_errors::DiagCtxtHandle;

use crate::coercion::DynamicCoerceMany;
use crate::fallback::DivergingFallbackBehavior;
@@ -217,6 +217,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
self.tcx
}

fn dcx(&self) -> DiagCtxtHandle<'_> {
self.root_ctxt.dcx()
}

fn item_def_id(&self) -> LocalDefId {
self.body_id
}
@@ -338,10 +342,6 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
Some(&self.infcx)
}

fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
self.infcx.set_tainted_by_errors(e)
}

fn lower_fn_sig(
&self,
decl: &rustc_hir::FnDecl<'tcx>,
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/method/confirm.rs
Original file line number Diff line number Diff line change
@@ -354,7 +354,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
let generics = self.tcx.generics_of(pick.item.def_id);

let arg_count_correct = check_generic_arg_count_for_call(
self.tcx,
self.fcx,
pick.item.def_id,
generics,
seg,
@@ -425,7 +425,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
}

let args = lower_generic_args(
self.tcx,
self.fcx,
pick.item.def_id,
parent_args,
false,
3 changes: 2 additions & 1 deletion compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
@@ -563,7 +563,8 @@ fn lint_literal<'tcx>(
ty::Float(t) => {
let is_infinite = match lit.node {
ast::LitKind::Float(v, _) => match t {
// FIXME(f16_f128): add this check once we have library support
// FIXME(f16_f128): add this check once `is_infinite` is reliable (ABI
// issues resolved).
ty::FloatTy::F16 => Ok(false),
ty::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
ty::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
14 changes: 11 additions & 3 deletions compiler/rustc_next_trait_solver/src/solve/mod.rs
Original file line number Diff line number Diff line change
@@ -48,12 +48,20 @@ enum GoalEvaluationKind {
Nested,
}

// FIXME(trait-system-refactor-initiative#117): we don't detect whether a response
// ended up pulling down any universes.
fn has_no_inference_or_external_constraints<I: Interner>(
response: ty::Canonical<I, Response<I>>,
) -> bool {
response.value.external_constraints.region_constraints.is_empty()
&& response.value.var_values.is_identity()
&& response.value.external_constraints.opaque_types.is_empty()
let ExternalConstraintsData {
ref region_constraints,
ref opaque_types,
ref normalization_nested_goals,
} = *response.value.external_constraints;
response.value.var_values.is_identity()
&& region_constraints.is_empty()
&& opaque_types.is_empty()
&& normalization_nested_goals.is_empty()
}

impl<'a, D, I> EvalCtxt<'a, D>
52 changes: 21 additions & 31 deletions compiler/rustc_next_trait_solver/src/solve/search_graph.rs
Original file line number Diff line number Diff line change
@@ -71,7 +71,7 @@ struct StackEntry<I: Interner> {
/// C :- D
/// D :- C
/// ```
cycle_participants: HashSet<CanonicalInput<I>>,
nested_goals: HashSet<CanonicalInput<I>>,
/// Starts out as `None` and gets set when rerunning this
/// goal in case we encounter a cycle.
provisional_result: Option<QueryResult<I>>,
@@ -139,18 +139,11 @@ impl<I: Interner> SearchGraph<I> {
self.mode
}

/// Pops the highest goal from the stack, lazily updating the
/// the next goal in the stack.
///
/// Directly popping from the stack instead of using this method
/// would cause us to not track overflow and recursion depth correctly.
fn pop_stack(&mut self) -> StackEntry<I> {
let elem = self.stack.pop().unwrap();
if let Some(last) = self.stack.raw.last_mut() {
last.reached_depth = last.reached_depth.max(elem.reached_depth);
last.encountered_overflow |= elem.encountered_overflow;
fn update_parent_goal(&mut self, reached_depth: StackDepth, encountered_overflow: bool) {
if let Some(parent) = self.stack.raw.last_mut() {
parent.reached_depth = parent.reached_depth.max(reached_depth);
parent.encountered_overflow |= encountered_overflow;
}
elem
}

pub(super) fn is_empty(&self) -> bool {
@@ -222,8 +215,8 @@ impl<I: Interner> SearchGraph<I> {
let current_cycle_root = &mut stack[current_root.as_usize()];
for entry in cycle_participants {
entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head));
current_cycle_root.cycle_participants.insert(entry.input);
current_cycle_root.cycle_participants.extend(mem::take(&mut entry.cycle_participants));
current_cycle_root.nested_goals.insert(entry.input);
current_cycle_root.nested_goals.extend(mem::take(&mut entry.nested_goals));
}
}

@@ -342,7 +335,7 @@ impl<I: Interner> SearchGraph<I> {
non_root_cycle_participant: None,
encountered_overflow: false,
has_been_used: HasBeenUsed::empty(),
cycle_participants: Default::default(),
nested_goals: Default::default(),
provisional_result: None,
};
assert_eq!(self.stack.push(entry), depth);
@@ -364,14 +357,16 @@ impl<I: Interner> SearchGraph<I> {
}

debug!("canonical cycle overflow");
let current_entry = self.pop_stack();
let current_entry = self.stack.pop().unwrap();
debug_assert!(current_entry.has_been_used.is_empty());
let result = Self::response_no_constraints(cx, input, Certainty::overflow(false));
(current_entry, result)
});

let proof_tree = inspect.finalize_canonical_goal_evaluation(cx);

self.update_parent_goal(final_entry.reached_depth, final_entry.encountered_overflow);

// We're now done with this goal. In case this goal is involved in a larger cycle
// do not remove it from the provisional cache and update its provisional result.
// We only add the root of cycles to the global cache.
@@ -394,15 +389,15 @@ impl<I: Interner> SearchGraph<I> {
//
// We must not use the global cache entry of a root goal if a cycle
// participant is on the stack. This is necessary to prevent unstable
// results. See the comment of `StackEntry::cycle_participants` for
// results. See the comment of `StackEntry::nested_goals` for
// more details.
self.global_cache(cx).insert(
cx,
input,
proof_tree,
reached_depth,
final_entry.encountered_overflow,
final_entry.cycle_participants,
final_entry.nested_goals,
dep_node,
result,
)
@@ -441,14 +436,9 @@ impl<I: Interner> SearchGraph<I> {
}
}

// Update the reached depth of the current goal to make sure
// its state is the same regardless of whether we've used the
// global cache or not.
// Adjust the parent goal as if we actually computed this goal.
let reached_depth = self.stack.next_index().plus(additional_depth);
if let Some(last) = self.stack.raw.last_mut() {
last.reached_depth = last.reached_depth.max(reached_depth);
last.encountered_overflow |= encountered_overflow;
}
self.update_parent_goal(reached_depth, encountered_overflow);

Some(result)
}
@@ -477,7 +467,7 @@ impl<I: Interner> SearchGraph<I> {
F: FnMut(&mut Self, &mut ProofTreeBuilder<D>) -> QueryResult<I>,
{
let result = prove_goal(self, inspect);
let stack_entry = self.pop_stack();
let stack_entry = self.stack.pop().unwrap();
debug_assert_eq!(stack_entry.input, input);

// If the current goal is not the root of a cycle, we are done.
@@ -554,27 +544,27 @@ impl<I: Interner> SearchGraph<I> {
non_root_cycle_participant,
encountered_overflow: _,
has_been_used,
ref cycle_participants,
ref nested_goals,
provisional_result,
} = *entry;
let cache_entry = provisional_cache.get(&entry.input).unwrap();
assert_eq!(cache_entry.stack_depth, Some(depth));
if let Some(head) = non_root_cycle_participant {
assert!(head < depth);
assert!(cycle_participants.is_empty());
assert!(nested_goals.is_empty());
assert_ne!(stack[head].has_been_used, HasBeenUsed::empty());

let mut current_root = head;
while let Some(parent) = stack[current_root].non_root_cycle_participant {
current_root = parent;
}
assert!(stack[current_root].cycle_participants.contains(&input));
assert!(stack[current_root].nested_goals.contains(&input));
}

if !cycle_participants.is_empty() {
if !nested_goals.is_empty() {
assert!(provisional_result.is_some() || !has_been_used.is_empty());
for entry in stack.iter().take(depth.as_usize()) {
assert_eq!(cycle_participants.get(&entry.input), None);
assert_eq!(nested_goals.get(&entry.input), None);
}
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
@@ -796,7 +796,7 @@ impl<'a> Parser<'a> {
self.dcx().struct_span_err(non_item_span, "non-item in item list");
self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
if is_let {
err.span_suggestion(
err.span_suggestion_verbose(
non_item_span,
"consider using `const` instead of `let` for associated const",
"const",
13 changes: 10 additions & 3 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -819,7 +819,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
}
ResolutionError::AttemptToUseNonConstantValueInConstant(ident, suggestion, current) => {
ResolutionError::AttemptToUseNonConstantValueInConstant {
ident,
suggestion,
current,
type_span,
} => {
// let foo =...
// ^^^ given this Span
// ------- get this Span to have an applicable suggestion
@@ -836,13 +841,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {

let ((with, with_label), without) = match sp {
Some(sp) if !self.tcx.sess.source_map().is_multiline(sp) => {
let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32)));
let sp = sp
.with_lo(BytePos(sp.lo().0 - (current.len() as u32)))
.until(ident.span);
(
(Some(errs::AttemptToUseNonConstantValueInConstantWithSuggestion {
span: sp,
ident,
suggestion,
current,
type_span,
}), Some(errs::AttemptToUseNonConstantValueInConstantLabelWithSuggestion {span})),
None,
)
12 changes: 7 additions & 5 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
@@ -240,16 +240,18 @@ pub(crate) struct AttemptToUseNonConstantValueInConstant<'a> {
}

#[derive(Subdiagnostic)]
#[suggestion(
#[multipart_suggestion(
resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion,
code = "{suggestion} {ident}",
applicability = "maybe-incorrect"
style = "verbose",
applicability = "has-placeholders"
)]
pub(crate) struct AttemptToUseNonConstantValueInConstantWithSuggestion<'a> {
#[primary_span]
// #[primary_span]
#[suggestion_part(code = "{suggestion} ")]
pub(crate) span: Span,
pub(crate) ident: Ident,
pub(crate) suggestion: &'a str,
#[suggestion_part(code = ": /* Type */")]
pub(crate) type_span: Option<Span>,
pub(crate) current: &'a str,
}

44 changes: 32 additions & 12 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
@@ -1178,21 +1178,41 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let Some(span) = finalize {
let (span, resolution_error) = match item {
None if rib_ident.as_str() == "self" => (span, LowercaseSelf),
None => (
rib_ident.span,
AttemptToUseNonConstantValueInConstant(
original_rib_ident_def,
"const",
"let",
),
),
None => {
// If we have a `let name = expr;`, we have the span for
// `name` and use that to see if it is followed by a type
// specifier. If not, then we know we need to suggest
// `const name: Ty = expr;`. This is a heuristic, it will
// break down in the presence of macros.
let sm = self.tcx.sess.source_map();
let type_span = match sm.span_look_ahead(
original_rib_ident_def.span,
":",
None,
) {
None => {
Some(original_rib_ident_def.span.shrink_to_hi())
}
Some(_) => None,
};
(
rib_ident.span,
AttemptToUseNonConstantValueInConstant {
ident: original_rib_ident_def,
suggestion: "const",
current: "let",
type_span,
},
)
}
Some((ident, kind)) => (
span,
AttemptToUseNonConstantValueInConstant(
AttemptToUseNonConstantValueInConstant {
ident,
"let",
kind.as_str(),
),
suggestion: "let",
current: kind.as_str(),
type_span: None,
},
),
};
self.report_error(span, resolution_error);
11 changes: 6 additions & 5 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
@@ -236,11 +236,12 @@ enum ResolutionError<'a> {
/// Error E0434: can't capture dynamic environment in a fn item.
CannotCaptureDynamicEnvironmentInFnItem,
/// Error E0435: attempt to use a non-constant value in a constant.
AttemptToUseNonConstantValueInConstant(
Ident,
/* suggestion */ &'static str,
/* current */ &'static str,
),
AttemptToUseNonConstantValueInConstant {
ident: Ident,
suggestion: &'static str,
current: &'static str,
type_span: Option<Span>,
},
/// Error E0530: `X` bindings cannot shadow `Y`s.
BindingShadowsSomethingUnacceptable {
shadowing_binding: PatternSource,
568 changes: 565 additions & 3 deletions compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// FIXME(error_reporting): This should be made into private methods on `TypeErrCtxt`.

use crate::infer::InferCtxt;
use crate::traits::{Obligation, ObligationCause, ObligationCtxt};
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, Diag};
@@ -9,8 +11,6 @@ use rustc_span::{Span, DUMMY_SP};

use super::ArgKind;

pub use rustc_infer::traits::error_reporting::*;

#[extension(pub trait InferCtxtExt<'tcx>)]
impl<'tcx> InferCtxt<'tcx> {
/// Given some node representing a fn-like thing in the HIR map,
273 changes: 208 additions & 65 deletions compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
// ignore-tidy-filelength :(

pub mod ambiguity;
mod fulfillment_errors;
mod infer_ctxt_ext;
pub mod on_unimplemented;
mod overflow;
pub mod suggestions;
mod type_err_ctxt_ext;

use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use std::iter;

use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode, PredicateObligation};
use rustc_hir::{self as hir, LangItem};
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::traits::{
Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError,
};
use rustc_macros::extension;
use rustc_middle::ty::print::PrintTraitRefExt as _;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
use std::ops::ControlFlow;
use rustc_span::{ErrorGuaranteed, ExpnKind, Span};

use ambiguity::TypeErrCtxtAmbiguityExt as _;
use fulfillment_errors::TypeErrCtxtExt as _;
use suggestions::TypeErrCtxtExt as _;

use crate::traits::{FulfillmentError, FulfillmentErrorCode};

pub use self::fulfillment_errors::*;
pub use self::infer_ctxt_ext::*;
pub use self::type_err_ctxt_ext::*;
pub use self::overflow::*;

// When outputting impl candidates, prefer showing those that are more similar.
//
@@ -89,49 +100,6 @@ impl<'v> Visitor<'v> for FindExprBySpan<'v> {
}
}

/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
/// `param: ?Sized` would be a valid constraint.
struct FindTypeParam {
param: rustc_span::Symbol,
invalid_spans: Vec<Span>,
nested: bool,
}

impl<'v> Visitor<'v> for FindTypeParam {
fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
// Skip where-clauses, to avoid suggesting indirection for type parameters found there.
}

fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
// We collect the spans of all uses of the "bare" type param, like in `field: T` or
// `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
// valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
// obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
// and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
// in that case should make what happened clear enough.
match ty.kind {
hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
hir::TyKind::Path(hir::QPath::Resolved(None, path))
if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
{
if !self.nested {
debug!(?ty, "FindTypeParam::visit_ty");
self.invalid_spans.push(ty.span);
}
}
hir::TyKind::Path(_) => {
let prev = self.nested;
self.nested = true;
hir::intravisit::walk_ty(self, ty);
self.nested = prev;
}
_ => {
hir::intravisit::walk_ty(self, ty);
}
}
}
}

/// Summarizes information
#[derive(Clone)]
pub enum ArgKind {
@@ -163,24 +131,199 @@ impl ArgKind {
}
}

struct HasNumericInferVisitor;
#[derive(Copy, Clone)]
pub enum DefIdOrName {
DefId(DefId),
Name(&'static str),
}

impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HasNumericInferVisitor {
type Result = ControlFlow<()>;
#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)]
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
fn report_fulfillment_errors(
&self,
mut errors: Vec<FulfillmentError<'tcx>>,
) -> ErrorGuaranteed {
self.sub_relations
.borrow_mut()
.add_constraints(self, errors.iter().map(|e| e.obligation.predicate));

#[derive(Debug)]
struct ErrorDescriptor<'tcx> {
predicate: ty::Predicate<'tcx>,
index: Option<usize>, // None if this is an old error
}

fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
let mut error_map: FxIndexMap<_, Vec<_>> = self
.reported_trait_errors
.borrow()
.iter()
.map(|(&span, predicates)| {
(
span,
predicates
.0
.iter()
.map(|&predicate| ErrorDescriptor { predicate, index: None })
.collect(),
)
})
.collect();

// Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics
// with more relevant type information and hide redundant E0282 errors.
errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) =>
{
1
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
ty::PredicateKind::Coerce(_) => 2,
_ => 0,
});

for (index, error) in errors.iter().enumerate() {
// We want to ignore desugarings here: spans are equivalent even
// if one is the result of a desugaring and the other is not.
let mut span = error.obligation.cause.span;
let expn_data = span.ctxt().outer_expn_data();
if let ExpnKind::Desugaring(_) = expn_data.kind {
span = expn_data.call_site;
}

error_map.entry(span).or_default().push(ErrorDescriptor {
predicate: error.obligation.predicate,
index: Some(index),
});
}

// We do this in 2 passes because we want to display errors in order, though
// maybe it *is* better to sort errors by span or something.
let mut is_suppressed = vec![false; errors.len()];
for (_, error_set) in error_map.iter() {
// We want to suppress "duplicate" errors with the same span.
for error in error_set {
if let Some(index) = error.index {
// Suppress errors that are either:
// 1) strictly implied by another error.
// 2) implied by an error with a smaller index.
for error2 in error_set {
if error2.index.is_some_and(|index2| is_suppressed[index2]) {
// Avoid errors being suppressed by already-suppressed
// errors, to prevent all errors from being suppressed
// at once.
continue;
}

if self.error_implies(error2.predicate, error.predicate)
&& !(error2.index >= error.index
&& self.error_implies(error.predicate, error2.predicate))
{
info!("skipping {:?} (implied by {:?})", error, error2);
is_suppressed[index] = true;
break;
}
}
}
}
}

let mut reported = None;

for from_expansion in [false, true] {
for (error, suppressed) in iter::zip(&errors, &is_suppressed) {
if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion {
let guar = self.report_fulfillment_error(error);
self.infcx.set_tainted_by_errors(guar);
reported = Some(guar);
// We want to ignore desugarings here: spans are equivalent even
// if one is the result of a desugaring and the other is not.
let mut span = error.obligation.cause.span;
let expn_data = span.ctxt().outer_expn_data();
if let ExpnKind::Desugaring(_) = expn_data.kind {
span = expn_data.call_site;
}
self.reported_trait_errors
.borrow_mut()
.entry(span)
.or_insert_with(|| (vec![], guar))
.0
.push(error.obligation.predicate);
}
}
}

// It could be that we don't report an error because we have seen an `ErrorReported` from
// another source. We should probably be able to fix most of these, but some are delayed
// bugs that get a proper error after this function.
reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
}
}

#[derive(Copy, Clone)]
pub enum DefIdOrName {
DefId(DefId),
Name(&'static str),
#[instrument(skip(self), level = "debug")]
fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed {
let mut error = FulfillmentError {
obligation: error.obligation.clone(),
code: error.code.clone(),
root_obligation: error.root_obligation.clone(),
};
if matches!(
error.code,
FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented)
| FulfillmentErrorCode::Project(_)
) && self.apply_do_not_recommend(&mut error.obligation)
{
error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented);
}

match error.code {
FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error(
error.obligation.clone(),
&error.root_obligation,
selection_error,
),
FulfillmentErrorCode::Project(ref e) => {
self.report_projection_error(&error.obligation, e)
}
FulfillmentErrorCode::Ambiguity { overflow: None } => {
self.maybe_report_ambiguity(&error.obligation)
}
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
}
FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
.report_mismatched_types(
&error.obligation.cause,
expected_found.expected,
expected_found.found,
*err,
)
.emit(),
FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
let mut diag = self.report_mismatched_consts(
&error.obligation.cause,
expected_found.expected,
expected_found.found,
*err,
);
let code = error.obligation.cause.code().peel_derives().peel_match_impls();
if let ObligationCauseCode::WhereClause(..)
| ObligationCauseCode::WhereClauseInExpr(..) = code
{
self.note_obligation_cause_code(
error.obligation.cause.body_id,
&mut diag,
error.obligation.predicate,
error.obligation.param_env,
code,
&mut vec![],
&mut Default::default(),
);
}
diag.emit()
}
FulfillmentErrorCode::Cycle(ref cycle) => self.report_overflow_obligation_cycle(cycle),
}
}
}

/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{ObligationCauseCode, PredicateObligation};
use crate::error_reporting::traits::type_err_ctxt_ext::InferCtxtPrivExt;
use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt;
use crate::errors::{
EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
};
197 changes: 197 additions & 0 deletions compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
use std::fmt;

use rustc_errors::{
struct_span_code_err, Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, E0275,
};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::traits::{Obligation, PredicateObligation};
use rustc_macros::extension;
use rustc_middle::ty::print::{FmtPrinter, Print};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Limit;
use rustc_span::Span;
use rustc_type_ir::Upcast;

use super::InferCtxtPrivExt;
use crate::error_reporting::traits::suggestions::TypeErrCtxtExt;

pub enum OverflowCause<'tcx> {
DeeplyNormalize(ty::AliasTerm<'tcx>),
TraitSolver(ty::Predicate<'tcx>),
}

pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
tcx: TyCtxt<'tcx>,
err: &mut Diag<'_, G>,
) {
let suggested_limit = match tcx.recursion_limit() {
Limit(0) => Limit(2),
limit => limit * 2,
};
err.help(format!(
"consider increasing the recursion limit by adding a \
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
suggested_limit,
tcx.crate_name(LOCAL_CRATE),
));
}

#[extension(pub trait TypeErrCtxtOverflowExt<'a, 'tcx>)]
impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
/// Reports that an overflow has occurred and halts compilation. We
/// halt compilation unconditionally because it is important that
/// overflows never be masked -- they basically represent computations
/// whose result could not be truly determined and thus we can't say
/// if the program type checks or not -- and they are unusual
/// occurrences in any case.
fn report_overflow_error(
&self,
cause: OverflowCause<'tcx>,
span: Span,
suggest_increasing_limit: bool,
mutate: impl FnOnce(&mut Diag<'_>),
) -> ! {
let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit);
mutate(&mut err);
err.emit();
FatalError.raise();
}

fn build_overflow_error(
&self,
cause: OverflowCause<'tcx>,
span: Span,
suggest_increasing_limit: bool,
) -> Diag<'a> {
fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String
where
T: fmt::Display + Print<'tcx, FmtPrinter<'tcx, 'tcx>>,
{
let s = value.to_string();
if s.len() > 50 {
// We don't need to save the type to a file, we will be talking about this type already
// in a separate note when we explain the obligation, so it will be available that way.
let mut cx: FmtPrinter<'_, '_> =
FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6));
value.print(&mut cx).unwrap();
cx.into_buffer()
} else {
s
}
}

let mut err = match cause {
OverflowCause::DeeplyNormalize(alias_term) => {
let alias_term = self.resolve_vars_if_possible(alias_term);
let kind = alias_term.kind(self.tcx).descr();
let alias_str = with_short_path(self.tcx, alias_term);
struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow normalizing the {kind} `{alias_str}`",
)
}
OverflowCause::TraitSolver(predicate) => {
let predicate = self.resolve_vars_if_possible(predicate);
match predicate.kind().skip_binder() {
ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ })
| ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow assigning `{a}` to `{b}`",
)
}
_ => {
let pred_str = with_short_path(self.tcx, predicate);
struct_span_code_err!(
self.dcx(),
span,
E0275,
"overflow evaluating the requirement `{pred_str}`",
)
}
}
}
};

if suggest_increasing_limit {
suggest_new_overflow_limit(self.tcx, &mut err);
}

err
}

/// Reports that an overflow has occurred and halts compilation. We
/// halt compilation unconditionally because it is important that
/// overflows never be masked -- they basically represent computations
/// whose result could not be truly determined and thus we can't say
/// if the program type checks or not -- and they are unusual
/// occurrences in any case.
fn report_overflow_obligation<T>(
&self,
obligation: &Obligation<'tcx, T>,
suggest_increasing_limit: bool,
) -> !
where
T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
{
let predicate = obligation.predicate.clone().upcast(self.tcx);
let predicate = self.resolve_vars_if_possible(predicate);
self.report_overflow_error(
OverflowCause::TraitSolver(predicate),
obligation.cause.span,
suggest_increasing_limit,
|err| {
self.note_obligation_cause_code(
obligation.cause.body_id,
err,
predicate,
obligation.param_env,
obligation.cause.code(),
&mut vec![],
&mut Default::default(),
);
},
);
}

/// Reports that a cycle was detected which led to overflow and halts
/// compilation. This is equivalent to `report_overflow_obligation` except
/// that we can give a more helpful error message (and, in particular,
/// we do not suggest increasing the overflow limit, which is not
/// going to help).
fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
let cycle = self.resolve_vars_if_possible(cycle.to_owned());
assert!(!cycle.is_empty());

debug!(?cycle, "report_overflow_error_cycle");

// The 'deepest' obligation is most likely to have a useful
// cause 'backtrace'
self.report_overflow_obligation(
cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(),
false,
);
}

fn report_overflow_no_abort(
&self,
obligation: PredicateObligation<'tcx>,
suggest_increasing_limit: bool,
) -> ErrorGuaranteed {
let obligation = self.resolve_vars_if_possible(obligation);
let mut err = self.build_overflow_error(
OverflowCause::TraitSolver(obligation.predicate),
obligation.cause.span,
suggest_increasing_limit,
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
err.emit()
}
}
Original file line number Diff line number Diff line change
@@ -44,7 +44,7 @@ use std::assert_matches::debug_assert_matches;
use std::borrow::Cow;
use std::iter;

use crate::error_reporting::traits::type_err_ctxt_ext::InferCtxtPrivExt;
use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt;
use crate::infer::InferCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_middle::ty::print::{
@@ -4623,6 +4623,132 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
);
}
}

#[instrument(level = "debug", skip_all)]
fn suggest_unsized_bound_if_applicable(
&self,
err: &mut Diag<'_>,
obligation: &PredicateObligation<'tcx>,
) {
let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
obligation.predicate.kind().skip_binder()
else {
return;
};
let (ObligationCauseCode::WhereClause(item_def_id, span)
| ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)) =
*obligation.cause.code().peel_derives()
else {
return;
};
if span.is_dummy() {
return;
}
debug!(?pred, ?item_def_id, ?span);

let (Some(node), true) = (
self.tcx.hir().get_if_local(item_def_id),
self.tcx.is_lang_item(pred.def_id(), LangItem::Sized),
) else {
return;
};

let Some(generics) = node.generics() else {
return;
};
let sized_trait = self.tcx.lang_items().sized_trait();
debug!(?generics.params);
debug!(?generics.predicates);
let Some(param) = generics.params.iter().find(|param| param.span == span) else {
return;
};
// Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
// `Sized` bound is there intentionally and we don't need to suggest relaxing it.
let explicitly_sized = generics
.bounds_for_param(param.def_id)
.flat_map(|bp| bp.bounds)
.any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
if explicitly_sized {
return;
}
debug!(?param);
match node {
hir::Node::Item(
item @ hir::Item {
// Only suggest indirection for uses of type parameters in ADTs.
kind:
hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
..
},
) => {
if self.suggest_indirection_for_unsized(err, item, param) {
return;
}
}
_ => {}
};

// Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
let (span, separator, open_paren_sp) =
if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
(s, " +", open_paren_sp)
} else {
(param.name.ident().span.shrink_to_hi(), ":", None)
};

let mut suggs = vec![];
let suggestion = format!("{separator} ?Sized");

if let Some(open_paren_sp) = open_paren_sp {
suggs.push((open_paren_sp, "(".to_string()));
suggs.push((span, format!("){suggestion}")));
} else {
suggs.push((span, suggestion));
}

err.multipart_suggestion_verbose(
"consider relaxing the implicit `Sized` restriction",
suggs,
Applicability::MachineApplicable,
);
}

fn suggest_indirection_for_unsized(
&self,
err: &mut Diag<'_>,
item: &hir::Item<'tcx>,
param: &hir::GenericParam<'tcx>,
) -> bool {
// Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
// borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
// is not. Look for invalid "bare" parameter uses, and suggest using indirection.
let mut visitor =
FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false };
visitor.visit_item(item);
if visitor.invalid_spans.is_empty() {
return false;
}
let mut multispan: MultiSpan = param.span.into();
multispan.push_span_label(
param.span,
format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
);
for sp in visitor.invalid_spans {
multispan.push_span_label(
sp,
format!("...if indirection were used here: `Box<{}>`", param.name.ident()),
);
}
err.span_help(
multispan,
format!(
"you could relax the implicit `Sized` bound on `{T}` if it were \
used through indirection like `&{T}` or `Box<{T}>`",
T = param.name.ident(),
),
);
true
}
}

/// Add a hint to add a missing borrow or remove an unnecessary one.
@@ -5126,3 +5252,46 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {

(ty, refs)
}

/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
/// `param: ?Sized` would be a valid constraint.
struct FindTypeParam {
param: rustc_span::Symbol,
invalid_spans: Vec<Span>,
nested: bool,
}

impl<'v> Visitor<'v> for FindTypeParam {
fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
// Skip where-clauses, to avoid suggesting indirection for type parameters found there.
}

fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
// We collect the spans of all uses of the "bare" type param, like in `field: T` or
// `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
// valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
// obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
// and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
// in that case should make what happened clear enough.
match ty.kind {
hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
hir::TyKind::Path(hir::QPath::Resolved(None, path))
if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
{
if !self.nested {
debug!(?ty, "FindTypeParam::visit_ty");
self.invalid_spans.push(ty.span);
}
}
hir::TyKind::Path(_) => {
let prev = self.nested;
self.nested = true;
hir::intravisit::walk_ty(self, ty);
self.nested = prev;
}
_ => {
hir::intravisit::walk_ty(self, ty);
}
}
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/solve/normalize.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt::Debug;
use std::marker::PhantomData;

use crate::error_reporting::traits::{OverflowCause, TypeErrCtxtExt};
use crate::error_reporting::traits::{OverflowCause, TypeErrCtxtOverflowExt};
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError};
use rustc_data_structures::stack::ensure_sufficient_stack;
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::error_reporting::traits::TypeErrCtxtExt;
use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
use crate::infer::{InferCtxt, TyOrConstInferVar};
use crate::traits::normalize::normalize_with_depth_to;
use rustc_data_structures::captures::Captures;
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/normalize.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
use super::SelectionContext;
use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
use crate::error_reporting::traits::OverflowCause;
use crate::error_reporting::traits::TypeErrCtxtExt;
use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
use crate::solve::NextSolverError;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::infer::at::At;
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
//! `normalize_canonicalized_projection_ty` query when it encounters projections.
use crate::error_reporting::traits::OverflowCause;
use crate::error_reporting::traits::TypeErrCtxtExt;
use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
use crate::infer::at::At;
use crate::infer::canonical::OriginalQueryValues;
use crate::infer::{InferCtxt, InferOk};
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ use super::{
TraitQueryMode,
};

use crate::error_reporting::traits::TypeErrCtxtExt;
use crate::error_reporting::traits::TypeErrCtxtOverflowExt;
use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener};
use crate::solve::InferCtxtSelectExt as _;
use crate::traits::normalize::normalize_with_depth;
2 changes: 1 addition & 1 deletion compiler/rustc_traits/src/codegen.rs
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::bug;
use rustc_middle::traits::CodegenObligationError;
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt;
use rustc_trait_selection::traits::{
ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext,
Unimplemented,
2 changes: 1 addition & 1 deletion compiler/rustc_traits/src/normalize_projection_ty.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::query::Providers;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt;
use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt;
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::query::{
normalize::NormalizationResult, CanonicalAliasGoal, NoSolution,
7 changes: 7 additions & 0 deletions library/core/src/error.rs
Original file line number Diff line number Diff line change
@@ -1008,8 +1008,15 @@ impl<'a> Iterator for Source<'a> {
self.current = self.current.and_then(Error::source);
current
}

fn size_hint(&self) -> (usize, Option<usize>) {
if self.current.is_some() { (1, None) } else { (0, Some(0)) }
}
}

#[unstable(feature = "error_iter", issue = "58520")]
impl<'a> crate::iter::FusedIterator for Source<'a> {}

#[stable(feature = "error_by_ref", since = "1.51.0")]
impl<'a, T: Error + ?Sized> Error for &'a T {
#[allow(deprecated, deprecated_in_future)]
3 changes: 2 additions & 1 deletion src/doc/rustdoc/src/advanced-features.md
Original file line number Diff line number Diff line change
@@ -80,7 +80,8 @@ pub struct BigX;
Then, when looking for it through the `rustdoc` search, if you enter "x" or
"big", search will show the `BigX` struct first.

There are some limitations on the doc alias names though: you can't use `"` or whitespace.
There are some limitations on the doc alias names though: they cannot contain quotes (`'`, `"`)
or most whitespace. ASCII space is allowed if it does not start or end the alias.

You can add multiple aliases at the same time by using a list:

40 changes: 25 additions & 15 deletions tests/ui/asm/parse-error.stderr
Original file line number Diff line number Diff line change
@@ -371,47 +371,57 @@ LL | global_asm!("{}", label {});
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/parse-error.rs:39:37
|
LL | let mut foo = 0;
| ----------- help: consider using `const` instead of `let`: `const foo`
...
LL | asm!("{}", options(), const foo);
| ^^^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const foo: /* Type */ = 0;
| ~~~~~ ++++++++++++

error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/parse-error.rs:71:44
|
LL | let mut foo = 0;
| ----------- help: consider using `const` instead of `let`: `const foo`
...
LL | asm!("{}", clobber_abi("C"), const foo);
| ^^^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const foo: /* Type */ = 0;
| ~~~~~ ++++++++++++

error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/parse-error.rs:74:55
|
LL | let mut foo = 0;
| ----------- help: consider using `const` instead of `let`: `const foo`
...
LL | asm!("{}", options(), clobber_abi("C"), const foo);
| ^^^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const foo: /* Type */ = 0;
| ~~~~~ ++++++++++++

error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/parse-error.rs:76:31
|
LL | let mut foo = 0;
| ----------- help: consider using `const` instead of `let`: `const foo`
...
LL | asm!("{a}", a = const foo, a = const bar);
| ^^^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const foo: /* Type */ = 0;
| ~~~~~ ++++++++++++

error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/parse-error.rs:76:46
|
LL | let mut bar = 0;
| ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{a}", a = const foo, a = const bar);
| ^^^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const bar: /* Type */ = 0;
| ~~~~~ ++++++++++++

error: aborting due to 64 previous errors

24 changes: 15 additions & 9 deletions tests/ui/asm/type-check-1.stderr
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/type-check-1.rs:41:26
|
LL | let x = 0;
| ----- help: consider using `const` instead of `let`: `const x`
...
LL | asm!("{}", const x);
| ^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const x: /* Type */ = 0;
| ~~~~~ ++++++++++++

error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/type-check-1.rs:44:36
|
LL | let x = 0;
| ----- help: consider using `const` instead of `let`: `const x`
...
LL | asm!("{}", const const_foo(x));
| ^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const x: /* Type */ = 0;
| ~~~~~ ++++++++++++

error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/type-check-1.rs:47:36
|
LL | let x = 0;
| ----- help: consider using `const` instead of `let`: `const x`
...
LL | asm!("{}", const const_bar(x));
| ^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const x: /* Type */ = 0;
| ~~~~~ ++++++++++++

error: invalid `sym` operand
--> $DIR/type-check-1.rs:49:24
24 changes: 15 additions & 9 deletions tests/ui/asm/x86_64/x86_64_parse_error.stderr
Original file line number Diff line number Diff line change
@@ -15,29 +15,35 @@ LL | asm!("{1}", in("eax") foo, const bar);
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/x86_64_parse_error.rs:13:46
|
LL | let mut bar = 0;
| ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{a}", in("eax") foo, a = const bar);
| ^^^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const bar: /* Type */ = 0;
| ~~~~~ ++++++++++++

error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/x86_64_parse_error.rs:15:46
|
LL | let mut bar = 0;
| ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{a}", in("eax") foo, a = const bar);
| ^^^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const bar: /* Type */ = 0;
| ~~~~~ ++++++++++++

error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/x86_64_parse_error.rs:17:42
|
LL | let mut bar = 0;
| ----------- help: consider using `const` instead of `let`: `const bar`
...
LL | asm!("{1}", in("eax") foo, const bar);
| ^^^ non-constant value
|
help: consider using `const` instead of `let`
|
LL | const bar: /* Type */ = 0;
| ~~~~~ ++++++++++++

error: aborting due to 5 previous errors

5 changes: 3 additions & 2 deletions tests/ui/associated-types/associated-types-eq-expr-path.rs
Original file line number Diff line number Diff line change
@@ -7,11 +7,12 @@ trait Foo {

impl Foo for isize {
type A = usize;
fn bar() -> isize { 42 }
fn bar() -> isize {
42
}
}

pub fn main() {
let x: isize = Foo::<A = usize>::bar();
//~^ ERROR associated item constraints are not allowed here
//~| ERROR cannot call
}
22 changes: 3 additions & 19 deletions tests/ui/associated-types/associated-types-eq-expr-path.stderr
Original file line number Diff line number Diff line change
@@ -1,25 +1,9 @@
error[E0229]: associated item constraints are not allowed here
--> $DIR/associated-types-eq-expr-path.rs:14:26
--> $DIR/associated-types-eq-expr-path.rs:16:26
|
LL | let x: isize = Foo::<A = usize>::bar();
| ^^^^^^^^^ associated item constraint not allowed here

error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/associated-types-eq-expr-path.rs:14:20
|
LL | fn bar() -> isize;
| ------------------ `Foo::bar` defined here
...
LL | let x: isize = Foo::<A = usize>::bar();
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
|
help: use the fully-qualified path to the only available implementation
|
LL - let x: isize = Foo::<A = usize>::bar();
LL + let x: isize = <isize as Foo<A = usize>>::bar();
|

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

Some errors have detailed explanations: E0229, E0790.
For more information about an error, try `rustc --explain E0229`.
For more information about this error, try `rustc --explain E0229`.
1 change: 0 additions & 1 deletion tests/ui/const-generics/assoc_const_as_type_argument.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@ fn foo<T: Trait>() {
bar::<<T as Trait>::ASSOC>();
//~^ ERROR: expected associated type, found associated constant `Trait::ASSOC`
//~| ERROR: unresolved item provided when a constant was expected
//~| ERROR type annotations needed
}

fn main() {}
18 changes: 3 additions & 15 deletions tests/ui/const-generics/assoc_const_as_type_argument.stderr
Original file line number Diff line number Diff line change
@@ -15,19 +15,7 @@ help: if this generic argument was intended as a const parameter, surround it wi
LL | bar::<{ <T as Trait>::ASSOC }>();
| + +

error[E0284]: type annotations needed
--> $DIR/assoc_const_as_type_argument.rs:8:5
|
LL | bar::<<T as Trait>::ASSOC>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `bar`
|
note: required by a const generic parameter in `bar`
--> $DIR/assoc_const_as_type_argument.rs:5:8
|
LL | fn bar<const N: usize>() {}
| ^^^^^^^^^^^^^^ required by this const generic parameter in `bar`

error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0284, E0575, E0747.
For more information about an error, try `rustc --explain E0284`.
Some errors have detailed explanations: E0575, E0747.
For more information about an error, try `rustc --explain E0575`.
Loading