t plit astconv's error report code in check functions to mod errors.

Move some error report codes to mod `astconv/errors.rs`
This commit is contained in:
surechen 2024-03-22 14:20:31 +08:00
parent 2531d08e34
commit 1012218ba8
7 changed files with 456 additions and 349 deletions

View File

@ -1,6 +1,6 @@
use crate::errors::{
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
ParenthesizedFnTraitExpansion,
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
};
use crate::fluent_generated as fluent;
use crate::hir_ty_lowering::HirTyLowerer;
@ -8,19 +8,26 @@ use crate::traits::error_reporting::report_object_safety_error;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::unord::UnordMap;
use rustc_errors::MultiSpan;
use rustc_errors::{
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::traits::FulfillmentError;
use rustc_middle::query::Key;
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{self, suggest_constraining_type_param};
use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{Binder, TraitRef};
use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{sym, Ident};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::BytePos;
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
use rustc_trait_selection::traits::{
object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
};
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
@ -1024,6 +1031,170 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Ok(())
}
}
pub fn report_prohibit_generics_error<'a>(
&self,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
err_extend: GenericsArgsErrExtend<'_>,
) -> ErrorGuaranteed {
#[derive(PartialEq, Eq, Hash)]
enum ProhibitGenericsArg {
Lifetime,
Type,
Const,
Infer,
}
let mut prohibit_args = FxIndexSet::default();
args_visitors.for_each(|arg| {
match arg {
hir::GenericArg::Lifetime(_) => prohibit_args.insert(ProhibitGenericsArg::Lifetime),
hir::GenericArg::Type(_) => prohibit_args.insert(ProhibitGenericsArg::Type),
hir::GenericArg::Const(_) => prohibit_args.insert(ProhibitGenericsArg::Const),
hir::GenericArg::Infer(_) => prohibit_args.insert(ProhibitGenericsArg::Infer),
};
});
let types_and_spans: Vec<_> = segments
.clone()
.flat_map(|segment| {
if segment.args().args.is_empty() {
None
} else {
Some((
match segment.res {
hir::def::Res::PrimTy(ty) => {
format!("{} `{}`", segment.res.descr(), ty.name())
}
hir::def::Res::Def(_, def_id)
if let Some(name) = self.tcx().opt_item_name(def_id) =>
{
format!("{} `{name}`", segment.res.descr())
}
hir::def::Res::Err => "this type".to_string(),
_ => segment.res.descr().to_string(),
},
segment.ident.span,
))
}
})
.collect();
let this_type = match &types_and_spans[..] {
[.., _, (last, _)] => format!(
"{} and {last}",
types_and_spans[..types_and_spans.len() - 1]
.iter()
.map(|(x, _)| x.as_str())
.intersperse(", ")
.collect::<String>()
),
[(only, _)] => only.to_string(),
[] => "this type".to_string(),
};
let arg_spans: Vec<Span> = segments
.clone()
.flat_map(|segment| segment.args().args)
.map(|arg| arg.span())
.collect();
let mut kinds = Vec::with_capacity(4);
prohibit_args.iter().for_each(|arg| match arg {
ProhibitGenericsArg::Lifetime => kinds.push("lifetime"),
ProhibitGenericsArg::Type => kinds.push("type"),
ProhibitGenericsArg::Const => kinds.push("const"),
ProhibitGenericsArg::Infer => kinds.push("generic"),
});
let (kind, s) = match kinds[..] {
[.., _, last] => (
format!(
"{} and {last}",
kinds[..kinds.len() - 1]
.iter()
.map(|&x| x)
.intersperse(", ")
.collect::<String>()
),
"s",
),
[only] => (only.to_string(), ""),
[] => unreachable!("expected at least one generic to prohibit"),
};
let last_span = *arg_spans.last().unwrap();
let span: MultiSpan = arg_spans.into();
let mut err = struct_span_code_err!(
self.tcx().dcx(),
span,
E0109,
"{kind} arguments are not allowed on {this_type}",
);
err.span_label(last_span, format!("{kind} argument{s} not allowed"));
for (what, span) in types_and_spans {
err.span_label(span, format!("not allowed on {what}"));
}
generics_args_err_extend(self.tcx(), segments.clone(), &mut err, err_extend);
let reported = err.emit();
self.set_tainted_by_errors(reported);
reported
}
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(),
additional_trait.bottom().1,
E0225,
"only auto traits can be used as additional traits in a trait object"
);
additional_trait.label_with_exp_info(
&mut err,
"additional non-auto trait",
"additional use",
);
first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
err.help(format!(
"consider creating a new trait with all of these as supertraits and using that \
trait here instead: `trait NewTrait: {} {{}}`",
regular_traits
.iter()
// FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
.map(|t| t.trait_ref().print_only_trait_path().to_string())
.collect::<Vec<_>>()
.join(" + "),
));
err.note(
"auto-traits like `Send` and `Sync` are traits that have special properties; \
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
}
pub fn report_trait_object_with_no_traits_error(
&self,
span: Span,
trait_bounds: &Vec<(Binder<'tcx, TraitRef<'tcx>>, Span)>,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let trait_alias_span = trait_bounds
.iter()
.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
}
}
/// Emits an error regarding forbidden type binding associations
@ -1031,7 +1202,7 @@ pub fn prohibit_assoc_item_binding(
tcx: TyCtxt<'_>,
span: Span,
segment: Option<(&hir::PathSegment<'_>, Span)>,
) {
) -> ErrorGuaranteed {
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
span,
fn_trait_expansion: if let Some((segment, span)) = segment
@ -1044,7 +1215,7 @@ pub fn prohibit_assoc_item_binding(
} else {
None
},
});
})
}
pub(crate) fn fn_trait_to_string(
@ -1099,3 +1270,208 @@ pub(crate) fn fn_trait_to_string(
format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
}
}
/// Used for generics args error extend.
pub enum GenericsArgsErrExtend<'tcx> {
EnumVariant {
qself: &'tcx hir::Ty<'tcx>,
assoc_segment: &'tcx hir::PathSegment<'tcx>,
adt_def: AdtDef<'tcx>,
},
OpaqueTy,
PrimTy(hir::PrimTy),
SelfTyAlias {
def_id: DefId,
span: Span,
},
SelfTyParam(Span),
TyParam(DefId),
DefVariant,
None,
}
fn generics_args_err_extend<'a>(
tcx: TyCtxt<'_>,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
err: &mut Diag<'_>,
err_extend: GenericsArgsErrExtend<'_>,
) {
match err_extend {
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => {
err.note("enum variants can't have type parameters");
let type_name = tcx.item_name(adt_def.did());
let msg = format!(
"you might have meant to specify type parameters on enum \
`{type_name}`"
);
let Some(args) = assoc_segment.args else {
return;
};
// Get the span of the generics args *including* the leading `::`.
// We do so by stretching args.span_ext to the left by 2. Earlier
// it was done based on the end of assoc segment but that sometimes
// led to impossible spans and caused issues like #116473
let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
if tcx.generics_of(adt_def.did()).count() == 0 {
// FIXME(estebank): we could also verify that the arguments being
// work for the `enum`, instead of just looking if it takes *any*.
err.span_suggestion_verbose(
args_span,
format!("{type_name} doesn't have generic parameters"),
"",
Applicability::MachineApplicable,
);
return;
}
let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
err.note(msg);
return;
};
let (qself_sugg_span, is_self) =
if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
// If the path segment already has type params, we want to overwrite
// them.
match &path.segments {
// `segment` is the previous to last element on the path,
// which would normally be the `enum` itself, while the last
// `_` `PathSegment` corresponds to the variant.
[
..,
hir::PathSegment {
ident, args, res: Res::Def(DefKind::Enum, _), ..
},
_,
] => (
// We need to include the `::` in `Type::Variant::<Args>`
// to point the span to `::<Args>`, not just `<Args>`.
ident
.span
.shrink_to_hi()
.to(args.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
false,
),
[segment] => {
(
// We need to include the `::` in `Type::Variant::<Args>`
// to point the span to `::<Args>`, not just `<Args>`.
segment.ident.span.shrink_to_hi().to(segment
.args
.map_or(segment.ident.span.shrink_to_hi(), |a| a.span_ext)),
kw::SelfUpper == segment.ident.name,
)
}
_ => {
err.note(msg);
return;
}
}
} else {
err.note(msg);
return;
};
let suggestion = vec![
if is_self {
// Account for people writing `Self::Variant::<Args>`, where
// `Self` is the enum, and suggest replacing `Self` with the
// appropriate type: `Type::<Args>::Variant`.
(qself.span, format!("{type_name}{snippet}"))
} else {
(qself_sugg_span, snippet)
},
(args_span, String::new()),
];
err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect);
}
GenericsArgsErrExtend::PrimTy(prim_ty) => {
let name = prim_ty.name_str();
for segment in segments {
if let Some(args) = segment.args {
err.span_suggestion_verbose(
segment.ident.span.shrink_to_hi().to(args.span_ext),
format!("primitive type `{name}` doesn't have generic parameters"),
"",
Applicability::MaybeIncorrect,
);
}
}
}
GenericsArgsErrExtend::OpaqueTy => {
err.note("`impl Trait` types can't have type parameters");
}
GenericsArgsErrExtend::DefVariant => {
err.note("enum variants can't have type parameters");
}
GenericsArgsErrExtend::TyParam(def_id) => {
if let Some(span) = tcx.def_ident_span(def_id) {
let name = tcx.item_name(def_id);
err.span_note(span, format!("type parameter `{name}` defined here"));
}
}
GenericsArgsErrExtend::SelfTyParam(span) => {
err.span_suggestion_verbose(
span,
"the `Self` type doesn't accept type parameters",
"",
Applicability::MaybeIncorrect,
);
}
GenericsArgsErrExtend::SelfTyAlias { def_id, span } => {
let ty = tcx.at(span).type_of(def_id).instantiate_identity();
let span_of_impl = tcx.span_of_impl(def_id);
let def_id = match *ty.kind() {
ty::Adt(self_def, _) => self_def.did(),
_ => return,
};
let type_name = tcx.item_name(def_id);
let span_of_ty = tcx.def_ident_span(def_id);
let generics = tcx.generics_of(def_id).count();
let msg = format!("`Self` is of type `{ty}`");
if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
let mut span: MultiSpan = vec![t_sp].into();
span.push_span_label(
i_sp,
format!("`Self` is on type `{type_name}` in this `impl`"),
);
let mut postfix = "";
if generics == 0 {
postfix = ", which doesn't have generic parameters";
}
span.push_span_label(t_sp, format!("`Self` corresponds to this type{postfix}"));
err.span_note(span, msg);
} else {
err.note(msg);
}
for segment in segments {
if let Some(args) = segment.args
&& segment.ident.name == kw::SelfUpper
{
if generics == 0 {
// FIXME(estebank): we could also verify that the arguments being
// work for the `enum`, instead of just looking if it takes *any*.
err.span_suggestion_verbose(
segment.ident.span.shrink_to_hi().to(args.span_ext),
"the `Self` type doesn't accept type parameters",
"",
Applicability::MachineApplicable,
);
return;
} else {
err.span_suggestion_verbose(
segment.ident.span,
format!(
"the `Self` type doesn't accept type parameters, use the \
concrete type's name `{type_name}` instead if you want to \
specify its type parameters"
),
type_name,
Applicability::MaybeIncorrect,
);
}
}
}
}
_ => {}
}
}

View File

@ -14,7 +14,7 @@
//! trait references and bounds.
mod bounds;
mod errors;
pub mod errors;
pub mod generics;
mod lint;
mod object_safety;
@ -22,14 +22,14 @@ mod object_safety;
use crate::bounds::Bounds;
use crate::collect::HirPlaceholderCollector;
use crate::errors::AmbiguousLifetimeBound;
use crate::hir_ty_lowering::errors::prohibit_assoc_item_binding;
use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend};
use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
use crate::middle::resolve_bound_vars as rbv;
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, MultiSpan,
codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@ -46,7 +46,7 @@ use rustc_middle::ty::{
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_target::spec::abi;
use rustc_trait_selection::traits::wf::object_region_bounds;
use rustc_trait_selection::traits::{self, ObligationCtxt};
@ -632,7 +632,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_ref: &hir::TraitRef<'tcx>,
self_ty: Ty<'tcx>,
) -> ty::TraitRef<'tcx> {
self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
let _ = self.prohibit_generic_args(
trait_ref.path.segments.split_last().unwrap().1.iter(),
GenericsArgsErrExtend::None,
);
self.lower_mono_trait_ref(
trait_ref.path.span,
@ -681,7 +684,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
let trait_segment = trait_ref.path.segments.last().unwrap();
self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
let _ = self.prohibit_generic_args(
trait_ref.path.segments.split_last().unwrap().1.iter(),
GenericsArgsErrExtend::None,
);
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
let (generic_args, arg_count) = self.lower_generic_args_of_path(
@ -995,8 +1001,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir_ref_id: hir::HirId,
span: Span,
qself_ty: Ty<'tcx>,
qself: &hir::Ty<'_>,
assoc_segment: &hir::PathSegment<'tcx>,
qself: &'tcx hir::Ty<'tcx>,
assoc_segment: &'tcx hir::PathSegment<'tcx>,
permit_variants: bool,
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
debug!(%qself_ty, ?assoc_segment.ident);
@ -1020,99 +1026,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
if let Some(variant_def) = variant_def {
if permit_variants {
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
self.prohibit_generic_args(slice::from_ref(assoc_segment).iter(), |err| {
err.note("enum variants can't have type parameters");
let type_name = tcx.item_name(adt_def.did());
let msg = format!(
"you might have meant to specify type parameters on enum \
`{type_name}`"
);
let Some(args) = assoc_segment.args else {
return;
};
// Get the span of the generics args *including* the leading `::`.
// We do so by stretching args.span_ext to the left by 2. Earlier
// it was done based on the end of assoc segment but that sometimes
// led to impossible spans and caused issues like #116473
let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
if tcx.generics_of(adt_def.did()).count() == 0 {
// FIXME(estebank): we could also verify that the arguments being
// work for the `enum`, instead of just looking if it takes *any*.
err.span_suggestion_verbose(
args_span,
format!("{type_name} doesn't have generic parameters"),
"",
Applicability::MachineApplicable,
);
return;
}
let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span)
else {
err.note(msg);
return;
};
let (qself_sugg_span, is_self) =
if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) =
&qself.kind
{
// If the path segment already has type params, we want to overwrite
// them.
match &path.segments {
// `segment` is the previous to last element on the path,
// which would normally be the `enum` itself, while the last
// `_` `PathSegment` corresponds to the variant.
[
..,
hir::PathSegment {
ident,
args,
res: Res::Def(DefKind::Enum, _),
..
},
_,
] => (
// We need to include the `::` in `Type::Variant::<Args>`
// to point the span to `::<Args>`, not just `<Args>`.
ident.span.shrink_to_hi().to(args
.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
false,
),
[segment] => (
// We need to include the `::` in `Type::Variant::<Args>`
// to point the span to `::<Args>`, not just `<Args>`.
segment.ident.span.shrink_to_hi().to(segment
.args
.map_or(segment.ident.span.shrink_to_hi(), |a| {
a.span_ext
})),
kw::SelfUpper == segment.ident.name,
),
_ => {
err.note(msg);
return;
}
}
} else {
err.note(msg);
return;
};
let suggestion = vec![
if is_self {
// Account for people writing `Self::Variant::<Args>`, where
// `Self` is the enum, and suggest replacing `Self` with the
// appropriate type: `Type::<Args>::Variant`.
(qself.span, format!("{type_name}{snippet}"))
} else {
(qself_sugg_span, snippet)
},
(args_span, String::new()),
];
err.multipart_suggestion_verbose(
msg,
suggestion,
Applicability::MaybeIncorrect,
);
});
let _ = self.prohibit_generic_args(
slice::from_ref(assoc_segment).iter(),
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
);
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
} else {
variant_resolution = Some(variant_def.def_id);
@ -1624,111 +1541,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
pub fn prohibit_generic_args<'a>(
&self,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
extend: impl Fn(&mut Diag<'_>),
) -> bool {
let args = segments.clone().flat_map(|segment| segment.args().args);
let (lt, ty, ct, inf) =
args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg {
hir::GenericArg::Lifetime(_) => (true, ty, ct, inf),
hir::GenericArg::Type(_) => (lt, true, ct, inf),
hir::GenericArg::Const(_) => (lt, ty, true, inf),
hir::GenericArg::Infer(_) => (lt, ty, ct, true),
});
let mut emitted = false;
if lt || ty || ct || inf {
let types_and_spans: Vec<_> = segments
.clone()
.flat_map(|segment| {
if segment.args().args.is_empty() {
None
} else {
Some((
match segment.res {
Res::PrimTy(ty) => {
format!("{} `{}`", segment.res.descr(), ty.name())
}
Res::Def(_, def_id)
if let Some(name) = self.tcx().opt_item_name(def_id) =>
{
format!("{} `{name}`", segment.res.descr())
}
Res::Err => "this type".to_string(),
_ => segment.res.descr().to_string(),
},
segment.ident.span,
))
}
})
.collect();
let this_type = match &types_and_spans[..] {
[.., _, (last, _)] => format!(
"{} and {last}",
types_and_spans[..types_and_spans.len() - 1]
.iter()
.map(|(x, _)| x.as_str())
.intersperse(", ")
.collect::<String>()
),
[(only, _)] => only.to_string(),
[] => "this type".to_string(),
};
let arg_spans: Vec<Span> = args.map(|arg| arg.span()).collect();
let mut kinds = Vec::with_capacity(4);
if lt {
kinds.push("lifetime");
}
if ty {
kinds.push("type");
}
if ct {
kinds.push("const");
}
if inf {
kinds.push("generic");
}
let (kind, s) = match kinds[..] {
[.., _, last] => (
format!(
"{} and {last}",
kinds[..kinds.len() - 1]
.iter()
.map(|&x| x)
.intersperse(", ")
.collect::<String>()
),
"s",
),
[only] => (only.to_string(), ""),
[] => unreachable!("expected at least one generic to prohibit"),
};
let last_span = *arg_spans.last().unwrap();
let span: MultiSpan = arg_spans.into();
let mut err = struct_span_code_err!(
self.tcx().dcx(),
span,
E0109,
"{kind} arguments are not allowed on {this_type}",
);
err.span_label(last_span, format!("{kind} argument{s} not allowed"));
for (what, span) in types_and_spans {
err.span_label(span, format!("not allowed on {what}"));
}
extend(&mut err);
self.set_tainted_by_errors(err.emit());
emitted = true;
err_extend: GenericsArgsErrExtend<'_>,
) -> Result<(), ErrorGuaranteed> {
let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
let mut result = Ok(());
if let Some(_) = args_visitors.clone().next() {
result = Err(self.report_prohibit_generics_error(
segments.clone(),
args_visitors,
err_extend,
));
}
for segment in segments {
// Only emit the first error to avoid overloading the user with error messages.
if let Some(b) = segment.args().bindings.first() {
prohibit_assoc_item_binding(self.tcx(), b.span, None);
return true;
return Err(prohibit_assoc_item_binding(self.tcx(), b.span, None));
}
}
emitted
result
}
/// Probe path segments that are semantically allowed to have generic arguments.
@ -1893,9 +1725,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Check for desugared `impl Trait`.
assert!(tcx.is_type_alias_impl_trait(did));
let item_segment = path.segments.split_last().unwrap();
self.prohibit_generic_args(item_segment.1.iter(), |err| {
err.note("`impl Trait` types can't have type parameters");
});
let _ = self
.prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy);
let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0);
Ty::new_opaque(tcx, did, args)
}
@ -1908,7 +1739,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
did,
) => {
assert_eq!(opt_self_ty, None);
self.prohibit_generic_args(path.segments.split_last().unwrap().1.iter(), |_| {});
let _ = self.prohibit_generic_args(
path.segments.split_last().unwrap().1.iter(),
GenericsArgsErrExtend::None,
);
self.lower_path_segment(span, did, path.segments.last().unwrap())
}
Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
@ -1920,13 +1754,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.probe_generic_path_segments(path.segments, None, kind, def_id, span);
let indices: FxHashSet<_> =
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
self.prohibit_generic_args(
let _ = self.prohibit_generic_args(
path.segments.iter().enumerate().filter_map(|(index, seg)| {
if !indices.contains(&index) { Some(seg) } else { None }
}),
|err| {
err.note("enum variants can't have type parameters");
},
GenericsArgsErrExtend::DefVariant,
);
let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
@ -1934,27 +1766,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
Res::Def(DefKind::TyParam, def_id) => {
assert_eq!(opt_self_ty, None);
self.prohibit_generic_args(path.segments.iter(), |err| {
if let Some(span) = tcx.def_ident_span(def_id) {
let name = tcx.item_name(def_id);
err.span_note(span, format!("type parameter `{name}` defined here"));
}
});
let _ = self.prohibit_generic_args(
path.segments.iter(),
GenericsArgsErrExtend::TyParam(def_id),
);
self.lower_ty_param(hir_id)
}
Res::SelfTyParam { .. } => {
// `Self` in trait or type alias.
assert_eq!(opt_self_ty, None);
self.prohibit_generic_args(path.segments.iter(), |err| {
let _ = self.prohibit_generic_args(
path.segments.iter(),
if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments {
err.span_suggestion_verbose(
GenericsArgsErrExtend::SelfTyParam(
ident.span.shrink_to_hi().to(args.span_ext),
"the `Self` type doesn't accept type parameters",
"",
Applicability::MaybeIncorrect,
);
}
});
)
} else {
GenericsArgsErrExtend::None
},
);
tcx.types.self_param
}
Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
@ -1962,65 +1792,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
assert_eq!(opt_self_ty, None);
// Try to evaluate any array length constants.
let ty = tcx.at(span).type_of(def_id).instantiate_identity();
let span_of_impl = tcx.span_of_impl(def_id);
self.prohibit_generic_args(path.segments.iter(), |err| {
let def_id = match *ty.kind() {
ty::Adt(self_def, _) => self_def.did(),
_ => return,
};
let type_name = tcx.item_name(def_id);
let span_of_ty = tcx.def_ident_span(def_id);
let generics = tcx.generics_of(def_id).count();
let msg = format!("`Self` is of type `{ty}`");
if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
let mut span: MultiSpan = vec![t_sp].into();
span.push_span_label(
i_sp,
format!("`Self` is on type `{type_name}` in this `impl`"),
);
let mut postfix = "";
if generics == 0 {
postfix = ", which doesn't have generic parameters";
}
span.push_span_label(
t_sp,
format!("`Self` corresponds to this type{postfix}"),
);
err.span_note(span, msg);
} else {
err.note(msg);
}
for segment in path.segments {
if let Some(args) = segment.args
&& segment.ident.name == kw::SelfUpper
{
if generics == 0 {
// FIXME(estebank): we could also verify that the arguments being
// work for the `enum`, instead of just looking if it takes *any*.
err.span_suggestion_verbose(
segment.ident.span.shrink_to_hi().to(args.span_ext),
"the `Self` type doesn't accept type parameters",
"",
Applicability::MachineApplicable,
);
return;
} else {
err.span_suggestion_verbose(
segment.ident.span,
format!(
"the `Self` type doesn't accept type parameters, use the \
concrete type's name `{type_name}` instead if you want to \
specify its type parameters"
),
type_name,
Applicability::MaybeIncorrect,
);
}
}
}
});
let _ = self.prohibit_generic_args(
path.segments.iter(),
GenericsArgsErrExtend::SelfTyAlias { def_id, span },
);
// HACK(min_const_generics): Forbid generic `Self` types
// here as we can't easily do that during nameres.
//
@ -2061,7 +1836,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
self.prohibit_generic_args(path.segments[..path.segments.len() - 2].iter(), |_| {});
let _ = self.prohibit_generic_args(
path.segments[..path.segments.len() - 2].iter(),
GenericsArgsErrExtend::None,
);
// HACK: until we support `<Type as ~const Trait>`, assume all of them are.
let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
ty::BoundConstness::ConstIfConst
@ -2079,19 +1857,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
Res::PrimTy(prim_ty) => {
assert_eq!(opt_self_ty, None);
self.prohibit_generic_args(path.segments.iter(), |err| {
let name = prim_ty.name_str();
for segment in path.segments {
if let Some(args) = segment.args {
err.span_suggestion_verbose(
segment.ident.span.shrink_to_hi().to(args.span_ext),
format!("primitive type `{name}` doesn't have generic parameters"),
"",
Applicability::MaybeIncorrect,
);
}
}
});
let _ = self.prohibit_generic_args(
path.segments.iter(),
GenericsArgsErrExtend::PrimTy(prim_ty),
);
match prim_ty {
hir::PrimTy::Bool => tcx.types.bool,
hir::PrimTy::Char => tcx.types.char,

View File

@ -1,5 +1,4 @@
use crate::bounds::Bounds;
use crate::errors::TraitObjectDeclaredWithNoTraits;
use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::{codes::*, struct_span_code_err};
@ -86,47 +85,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
if regular_traits.len() > 1 {
let first_trait = &regular_traits[0];
let additional_trait = &regular_traits[1];
let mut err = struct_span_code_err!(
tcx.dcx(),
additional_trait.bottom().1,
E0225,
"only auto traits can be used as additional traits in a trait object"
);
additional_trait.label_with_exp_info(
&mut err,
"additional non-auto trait",
"additional use",
);
first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
err.help(format!(
"consider creating a new trait with all of these as supertraits and using that \
trait here instead: `trait NewTrait: {} {{}}`",
regular_traits
.iter()
// FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
.map(|t| t.trait_ref().print_only_trait_path().to_string())
.collect::<Vec<_>>()
.join(" + "),
));
err.note(
"auto-traits like `Send` and `Sync` are traits that have special properties; \
for more information on them, visit \
<https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
);
self.set_tainted_by_errors(err.emit());
}
if regular_traits.is_empty() && auto_traits.is_empty() {
let trait_alias_span = trait_bounds
.iter()
.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);
let _ = self.report_trait_object_addition_traits_error(&regular_traits);
} else if regular_traits.is_empty() && auto_traits.is_empty() {
let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
return Ty::new_error(tcx, reported);
}

View File

@ -11,6 +11,7 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
use rustc_hir_analysis::hir_ty_lowering::generics::{
check_generic_arg_count_for_call, lower_generic_args,
};
@ -1177,11 +1178,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let indices: FxHashSet<_> =
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
let generics_has_err = self.lowerer().prohibit_generic_args(
let generics_err = self.lowerer().prohibit_generic_args(
segments.iter().enumerate().filter_map(|(index, seg)| {
if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None }
}),
|_| {},
GenericsArgsErrExtend::None,
);
if let Res::Local(hid) = res {
@ -1191,7 +1192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return (ty, res);
}
if generics_has_err {
if let Err(_) = generics_err {
// Don't try to infer type parameters when prohibited generic arguments were given.
user_self_ty = None;
}

View File

@ -65,7 +65,7 @@ pub use self::util::{
check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds,
transitive_bounds_that_define_assoc_item, SupertraitDefIds,
};
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};

View File

@ -2,6 +2,6 @@ fn main() {
let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
//~^ ERROR expected a pattern, found an expression
//~| ERROR cannot find type `T` in this scope
//~| ERROR type and const arguments are not allowed on builtin type `str`
//~| ERROR const and type arguments are not allowed on builtin type `str`
//~| ERROR expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes`
}

View File

@ -10,11 +10,11 @@ error[E0412]: cannot find type `T` in this scope
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
| ^ not found in this scope
error[E0109]: type and const arguments are not allowed on builtin type `str`
error[E0109]: const and type arguments are not allowed on builtin type `str`
--> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:15
|
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
| --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ type and const arguments not allowed
| --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ const and type arguments not allowed
| |
| not allowed on builtin type `str`
|