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:
parent
2531d08e34
commit
1012218ba8
@ -1,6 +1,6 @@
|
|||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
|
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
|
||||||
ParenthesizedFnTraitExpansion,
|
ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
|
||||||
};
|
};
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
use crate::hir_ty_lowering::HirTyLowerer;
|
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::fx::{FxIndexMap, FxIndexSet};
|
||||||
use rustc_data_structures::sorted_map::SortedMap;
|
use rustc_data_structures::sorted_map::SortedMap;
|
||||||
use rustc_data_structures::unord::UnordMap;
|
use rustc_data_structures::unord::UnordMap;
|
||||||
|
use rustc_errors::MultiSpan;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
|
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
|
||||||
};
|
};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_infer::traits::FulfillmentError;
|
use rustc_infer::traits::FulfillmentError;
|
||||||
use rustc_middle::query::Key;
|
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_session::parse::feature_err;
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
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_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> + '_ {
|
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
|
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
|
||||||
@ -1024,6 +1031,170 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
Ok(())
|
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 = ®ular_traits[0];
|
||||||
|
let additional_trait = ®ular_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
|
/// Emits an error regarding forbidden type binding associations
|
||||||
@ -1031,7 +1202,7 @@ pub fn prohibit_assoc_item_binding(
|
|||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
segment: Option<(&hir::PathSegment<'_>, Span)>,
|
segment: Option<(&hir::PathSegment<'_>, Span)>,
|
||||||
) {
|
) -> ErrorGuaranteed {
|
||||||
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
|
tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
|
||||||
span,
|
span,
|
||||||
fn_trait_expansion: if let Some((segment, span)) = segment
|
fn_trait_expansion: if let Some((segment, span)) = segment
|
||||||
@ -1044,7 +1215,7 @@ pub fn prohibit_assoc_item_binding(
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fn_trait_to_string(
|
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)
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
//! trait references and bounds.
|
//! trait references and bounds.
|
||||||
|
|
||||||
mod bounds;
|
mod bounds;
|
||||||
mod errors;
|
pub mod errors;
|
||||||
pub mod generics;
|
pub mod generics;
|
||||||
mod lint;
|
mod lint;
|
||||||
mod object_safety;
|
mod object_safety;
|
||||||
@ -22,14 +22,14 @@ mod object_safety;
|
|||||||
use crate::bounds::Bounds;
|
use crate::bounds::Bounds;
|
||||||
use crate::collect::HirPlaceholderCollector;
|
use crate::collect::HirPlaceholderCollector;
|
||||||
use crate::errors::AmbiguousLifetimeBound;
|
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::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
|
||||||
use crate::middle::resolve_bound_vars as rbv;
|
use crate::middle::resolve_bound_vars as rbv;
|
||||||
use crate::require_c_abi_if_c_variadic;
|
use crate::require_c_abi_if_c_variadic;
|
||||||
use rustc_ast::TraitObjectSyntax;
|
use rustc_ast::TraitObjectSyntax;
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||||
use rustc_errors::{
|
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 as hir;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
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_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
use rustc_span::edit_distance::find_best_match_for_name;
|
||||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
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_target::spec::abi;
|
||||||
use rustc_trait_selection::traits::wf::object_region_bounds;
|
use rustc_trait_selection::traits::wf::object_region_bounds;
|
||||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||||
@ -632,7 +632,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
trait_ref: &hir::TraitRef<'tcx>,
|
trait_ref: &hir::TraitRef<'tcx>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
) -> ty::TraitRef<'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(
|
self.lower_mono_trait_ref(
|
||||||
trait_ref.path.span,
|
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_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
|
||||||
let trait_segment = trait_ref.path.segments.last().unwrap();
|
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);
|
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
|
||||||
|
|
||||||
let (generic_args, arg_count) = self.lower_generic_args_of_path(
|
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,
|
hir_ref_id: hir::HirId,
|
||||||
span: Span,
|
span: Span,
|
||||||
qself_ty: Ty<'tcx>,
|
qself_ty: Ty<'tcx>,
|
||||||
qself: &hir::Ty<'_>,
|
qself: &'tcx hir::Ty<'tcx>,
|
||||||
assoc_segment: &hir::PathSegment<'tcx>,
|
assoc_segment: &'tcx hir::PathSegment<'tcx>,
|
||||||
permit_variants: bool,
|
permit_variants: bool,
|
||||||
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
|
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
|
||||||
debug!(%qself_ty, ?assoc_segment.ident);
|
debug!(%qself_ty, ?assoc_segment.ident);
|
||||||
@ -1020,99 +1026,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
if let Some(variant_def) = variant_def {
|
if let Some(variant_def) = variant_def {
|
||||||
if permit_variants {
|
if permit_variants {
|
||||||
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
|
tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
|
||||||
self.prohibit_generic_args(slice::from_ref(assoc_segment).iter(), |err| {
|
let _ = self.prohibit_generic_args(
|
||||||
err.note("enum variants can't have type parameters");
|
slice::from_ref(assoc_segment).iter(),
|
||||||
let type_name = tcx.item_name(adt_def.did());
|
GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
|
||||||
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,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
|
return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
|
||||||
} else {
|
} else {
|
||||||
variant_resolution = Some(variant_def.def_id);
|
variant_resolution = Some(variant_def.def_id);
|
||||||
@ -1624,111 +1541,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
pub fn prohibit_generic_args<'a>(
|
pub fn prohibit_generic_args<'a>(
|
||||||
&self,
|
&self,
|
||||||
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
|
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
|
||||||
extend: impl Fn(&mut Diag<'_>),
|
err_extend: GenericsArgsErrExtend<'_>,
|
||||||
) -> bool {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let args = segments.clone().flat_map(|segment| segment.args().args);
|
let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
|
||||||
|
let mut result = Ok(());
|
||||||
let (lt, ty, ct, inf) =
|
if let Some(_) = args_visitors.clone().next() {
|
||||||
args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg {
|
result = Err(self.report_prohibit_generics_error(
|
||||||
hir::GenericArg::Lifetime(_) => (true, ty, ct, inf),
|
segments.clone(),
|
||||||
hir::GenericArg::Type(_) => (lt, true, ct, inf),
|
args_visitors,
|
||||||
hir::GenericArg::Const(_) => (lt, ty, true, inf),
|
err_extend,
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for segment in segments {
|
for segment in segments {
|
||||||
// Only emit the first error to avoid overloading the user with error messages.
|
// Only emit the first error to avoid overloading the user with error messages.
|
||||||
if let Some(b) = segment.args().bindings.first() {
|
if let Some(b) = segment.args().bindings.first() {
|
||||||
prohibit_assoc_item_binding(self.tcx(), b.span, None);
|
return Err(prohibit_assoc_item_binding(self.tcx(), b.span, None));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emitted
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Probe path segments that are semantically allowed to have generic arguments.
|
/// 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`.
|
// Check for desugared `impl Trait`.
|
||||||
assert!(tcx.is_type_alias_impl_trait(did));
|
assert!(tcx.is_type_alias_impl_trait(did));
|
||||||
let item_segment = path.segments.split_last().unwrap();
|
let item_segment = path.segments.split_last().unwrap();
|
||||||
self.prohibit_generic_args(item_segment.1.iter(), |err| {
|
let _ = self
|
||||||
err.note("`impl Trait` types can't have type parameters");
|
.prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy);
|
||||||
});
|
|
||||||
let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0);
|
let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0);
|
||||||
Ty::new_opaque(tcx, did, args)
|
Ty::new_opaque(tcx, did, args)
|
||||||
}
|
}
|
||||||
@ -1908,7 +1739,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
did,
|
did,
|
||||||
) => {
|
) => {
|
||||||
assert_eq!(opt_self_ty, None);
|
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())
|
self.lower_path_segment(span, did, path.segments.last().unwrap())
|
||||||
}
|
}
|
||||||
Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
|
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);
|
self.probe_generic_path_segments(path.segments, None, kind, def_id, span);
|
||||||
let indices: FxHashSet<_> =
|
let indices: FxHashSet<_> =
|
||||||
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
|
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)| {
|
path.segments.iter().enumerate().filter_map(|(index, seg)| {
|
||||||
if !indices.contains(&index) { Some(seg) } else { None }
|
if !indices.contains(&index) { Some(seg) } else { None }
|
||||||
}),
|
}),
|
||||||
|err| {
|
GenericsArgsErrExtend::DefVariant,
|
||||||
err.note("enum variants can't have type parameters");
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
|
let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
|
||||||
@ -1934,27 +1766,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
}
|
}
|
||||||
Res::Def(DefKind::TyParam, def_id) => {
|
Res::Def(DefKind::TyParam, def_id) => {
|
||||||
assert_eq!(opt_self_ty, None);
|
assert_eq!(opt_self_ty, None);
|
||||||
self.prohibit_generic_args(path.segments.iter(), |err| {
|
let _ = self.prohibit_generic_args(
|
||||||
if let Some(span) = tcx.def_ident_span(def_id) {
|
path.segments.iter(),
|
||||||
let name = tcx.item_name(def_id);
|
GenericsArgsErrExtend::TyParam(def_id),
|
||||||
err.span_note(span, format!("type parameter `{name}` defined here"));
|
);
|
||||||
}
|
|
||||||
});
|
|
||||||
self.lower_ty_param(hir_id)
|
self.lower_ty_param(hir_id)
|
||||||
}
|
}
|
||||||
Res::SelfTyParam { .. } => {
|
Res::SelfTyParam { .. } => {
|
||||||
// `Self` in trait or type alias.
|
// `Self` in trait or type alias.
|
||||||
assert_eq!(opt_self_ty, None);
|
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 {
|
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),
|
ident.span.shrink_to_hi().to(args.span_ext),
|
||||||
"the `Self` type doesn't accept type parameters",
|
)
|
||||||
"",
|
} else {
|
||||||
Applicability::MaybeIncorrect,
|
GenericsArgsErrExtend::None
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
|
||||||
});
|
|
||||||
tcx.types.self_param
|
tcx.types.self_param
|
||||||
}
|
}
|
||||||
Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
|
Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
|
||||||
@ -1962,65 +1792,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
assert_eq!(opt_self_ty, None);
|
assert_eq!(opt_self_ty, None);
|
||||||
// Try to evaluate any array length constants.
|
// Try to evaluate any array length constants.
|
||||||
let ty = tcx.at(span).type_of(def_id).instantiate_identity();
|
let ty = tcx.at(span).type_of(def_id).instantiate_identity();
|
||||||
let span_of_impl = tcx.span_of_impl(def_id);
|
let _ = self.prohibit_generic_args(
|
||||||
self.prohibit_generic_args(path.segments.iter(), |err| {
|
path.segments.iter(),
|
||||||
let def_id = match *ty.kind() {
|
GenericsArgsErrExtend::SelfTyAlias { def_id, span },
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// HACK(min_const_generics): Forbid generic `Self` types
|
// HACK(min_const_generics): Forbid generic `Self` types
|
||||||
// here as we can't easily do that during nameres.
|
// 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) => {
|
Res::Def(DefKind::AssocTy, def_id) => {
|
||||||
debug_assert!(path.segments.len() >= 2);
|
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.
|
// 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) {
|
let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
|
||||||
ty::BoundConstness::ConstIfConst
|
ty::BoundConstness::ConstIfConst
|
||||||
@ -2079,19 +1857,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
}
|
}
|
||||||
Res::PrimTy(prim_ty) => {
|
Res::PrimTy(prim_ty) => {
|
||||||
assert_eq!(opt_self_ty, None);
|
assert_eq!(opt_self_ty, None);
|
||||||
self.prohibit_generic_args(path.segments.iter(), |err| {
|
let _ = self.prohibit_generic_args(
|
||||||
let name = prim_ty.name_str();
|
path.segments.iter(),
|
||||||
for segment in path.segments {
|
GenericsArgsErrExtend::PrimTy(prim_ty),
|
||||||
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,
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
match prim_ty {
|
match prim_ty {
|
||||||
hir::PrimTy::Bool => tcx.types.bool,
|
hir::PrimTy::Bool => tcx.types.bool,
|
||||||
hir::PrimTy::Char => tcx.types.char,
|
hir::PrimTy::Char => tcx.types.char,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::bounds::Bounds;
|
use crate::bounds::Bounds;
|
||||||
use crate::errors::TraitObjectDeclaredWithNoTraits;
|
|
||||||
use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
|
use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||||
use rustc_errors::{codes::*, struct_span_code_err};
|
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<_>) =
|
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
|
||||||
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
|
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
|
||||||
if regular_traits.len() > 1 {
|
if regular_traits.len() > 1 {
|
||||||
let first_trait = ®ular_traits[0];
|
let _ = self.report_trait_object_addition_traits_error(®ular_traits);
|
||||||
let additional_trait = ®ular_traits[1];
|
} else if regular_traits.is_empty() && auto_traits.is_empty() {
|
||||||
let mut err = struct_span_code_err!(
|
let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
|
||||||
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);
|
|
||||||
return Ty::new_error(tcx, reported);
|
return Ty::new_error(tcx, reported);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
|
|||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
|
use rustc_hir::{ExprKind, GenericArg, Node, QPath};
|
||||||
|
use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
|
||||||
use rustc_hir_analysis::hir_ty_lowering::generics::{
|
use rustc_hir_analysis::hir_ty_lowering::generics::{
|
||||||
check_generic_arg_count_for_call, lower_generic_args,
|
check_generic_arg_count_for_call, lower_generic_args,
|
||||||
};
|
};
|
||||||
@ -1177,11 +1178,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
let indices: FxHashSet<_> =
|
let indices: FxHashSet<_> =
|
||||||
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
|
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)| {
|
segments.iter().enumerate().filter_map(|(index, seg)| {
|
||||||
if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None }
|
if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None }
|
||||||
}),
|
}),
|
||||||
|_| {},
|
GenericsArgsErrExtend::None,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Res::Local(hid) = res {
|
if let Res::Local(hid) = res {
|
||||||
@ -1191,7 +1192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
return (ty, res);
|
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.
|
// Don't try to infer type parameters when prohibited generic arguments were given.
|
||||||
user_self_ty = None;
|
user_self_ty = None;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ pub use self::util::{
|
|||||||
check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds,
|
check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds,
|
||||||
transitive_bounds_that_define_assoc_item, SupertraitDefIds,
|
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::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
|
||||||
pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
|
pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
|
||||||
|
|
||||||
|
@ -2,6 +2,6 @@ fn main() {
|
|||||||
let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
||||||
//~^ ERROR expected a pattern, found an expression
|
//~^ ERROR expected a pattern, found an expression
|
||||||
//~| ERROR cannot find type `T` in this scope
|
//~| 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`
|
//~| ERROR expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes`
|
||||||
}
|
}
|
||||||
|
@ -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;
|
LL | let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
|
||||||
| ^ not found in this scope
|
| ^ 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
|
--> $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;
|
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`
|
| not allowed on builtin type `str`
|
||||||
|
|
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user