Rollup merge of #122527 - fmease:clean-up-hir-ty-lowering, r=compiler-errors

Clean up AstConv

Split off from #120926 to make it only contain the renaming & (doc) comment updates.
Any changes other than that which have accumulated over time are now part of this PR.
Let's be disciplined ;) Inspired by https://github.com/rust-lang/rust/pull/120926#issuecomment-1997984483.

---

* Remove `hir_trait_to_predicates`
  * Unused since #113671
* Inline `create_args_for_ast_trait_ref`
  * Only had a single call site
  * Having it as a separate method didn't gain us anything
* Use an if-let guard somewhere to avoid unwrapping
* Avoid explicit trait object lifetimes
  * More legible, stylistic-only (the updated code is 100% semantically identical)
  * Use explicitly elided lifetimes in impl headers, they get elaborated to distinct lifetimes
  * Make use of [object lifetime defaulting](https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes) for a trait object type inside of a reference type somewhere
* Use preexisting dedicated method `ItemCtxt::to_ty` over `<dyn AstConv<'_>>::ast_ty_to_ty`
* Use preexisting dedicated method `AstConv::astconv` over explicit coercions
* Simplify the function signature of `create_args_for_ast_path` and of `check_generic_arg_count`
  * In both cases redundant information was passed rendering the call sites verbose and confusing
  * No perf impact (tested in [#120926](https://github.com/rust-lang/rust/pull/120926))
* Move diagnostic method `report_ambiguous_associated_type` from `astconv` to `astconv::errors`
  * The submodule `errors` exists specifically for that purpose
  * Use it to keep the main module clean & short
This commit is contained in:
Matthias Krüger 2024-03-15 10:14:56 +01:00 committed by GitHub
commit 277df5e176
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 142 additions and 208 deletions

View File

@ -22,7 +22,7 @@
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
impl<'tcx> dyn AstConv<'tcx> + '_ {
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
/// the type parameter's name as a placeholder.
pub(crate) fn complain_about_missing_type_params(
@ -349,6 +349,118 @@ fn complain_about_assoc_kind_mismatch(
})
}
pub(super) fn report_ambiguous_associated_type(
&self,
span: Span,
types: &[String],
traits: &[String],
name: Symbol,
) -> ErrorGuaranteed {
let mut err =
struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type");
if self
.tcx()
.resolutions(())
.confused_type_with_std_module
.keys()
.any(|full_span| full_span.contains(span))
{
err.span_suggestion_verbose(
span.shrink_to_lo(),
"you are looking for the module in `std`, not the primitive type",
"std::",
Applicability::MachineApplicable,
);
} else {
let mut types = types.to_vec();
types.sort();
let mut traits = traits.to_vec();
traits.sort();
match (&types[..], &traits[..]) {
([], []) => {
err.span_suggestion_verbose(
span,
format!(
"if there were a type named `Type` that implements a trait named \
`Trait` with associated type `{name}`, you could use the \
fully-qualified path",
),
format!("<Type as Trait>::{name}"),
Applicability::HasPlaceholders,
);
}
([], [trait_str]) => {
err.span_suggestion_verbose(
span,
format!(
"if there were a type named `Example` that implemented `{trait_str}`, \
you could use the fully-qualified path",
),
format!("<Example as {trait_str}>::{name}"),
Applicability::HasPlaceholders,
);
}
([], traits) => {
err.span_suggestions(
span,
format!(
"if there were a type named `Example` that implemented one of the \
traits with associated type `{name}`, you could use the \
fully-qualified path",
),
traits
.iter()
.map(|trait_str| format!("<Example as {trait_str}>::{name}"))
.collect::<Vec<_>>(),
Applicability::HasPlaceholders,
);
}
([type_str], []) => {
err.span_suggestion_verbose(
span,
format!(
"if there were a trait named `Example` with associated type `{name}` \
implemented for `{type_str}`, you could use the fully-qualified path",
),
format!("<{type_str} as Example>::{name}"),
Applicability::HasPlaceholders,
);
}
(types, []) => {
err.span_suggestions(
span,
format!(
"if there were a trait named `Example` with associated type `{name}` \
implemented for one of the types, you could use the fully-qualified \
path",
),
types
.into_iter()
.map(|type_str| format!("<{type_str} as Example>::{name}")),
Applicability::HasPlaceholders,
);
}
(types, traits) => {
let mut suggestions = vec![];
for type_str in types {
for trait_str in traits {
suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
}
}
err.span_suggestions(
span,
"use fully-qualified syntax",
suggestions,
Applicability::MachineApplicable,
);
}
}
}
let reported = err.emit();
self.set_tainted_by_errors(reported);
reported
}
pub(crate) fn complain_about_ambiguous_inherent_assoc_type(
&self,
name: Ident,

View File

@ -409,15 +409,12 @@ pub fn check_generic_arg_count_for_call(
seg: &hir::PathSegment<'_>,
is_method_call: IsMethodCall,
) -> GenericArgCountResult {
let empty_args = hir::GenericArgs::none();
let gen_args = seg.args.unwrap_or(&empty_args);
let gen_pos = match is_method_call {
IsMethodCall::Yes => GenericArgPosition::MethodCall,
IsMethodCall::No => GenericArgPosition::Value,
};
let has_self = generics.parent.is_none() && generics.has_self;
check_generic_arg_count(tcx, def_id, seg, generics, gen_args, gen_pos, has_self, seg.infer_args)
check_generic_arg_count(tcx, def_id, seg, generics, gen_pos, has_self)
}
/// Checks that the correct number of generic arguments have been provided.
@ -428,11 +425,10 @@ pub(crate) fn check_generic_arg_count(
def_id: DefId,
seg: &hir::PathSegment<'_>,
gen_params: &ty::Generics,
gen_args: &hir::GenericArgs<'_>,
gen_pos: GenericArgPosition,
has_self: bool,
infer_args: bool,
) -> GenericArgCountResult {
let gen_args = seg.args();
let default_counts = gen_params.own_defaults();
let param_counts = gen_params.own_counts();
@ -453,7 +449,7 @@ pub(crate) fn check_generic_arg_count(
.count();
let named_const_param_count = param_counts.consts - synth_const_param_count;
let infer_lifetimes =
(gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
(gen_pos != GenericArgPosition::Type || seg.infer_args) && !gen_args.has_lifetime_params();
if gen_pos != GenericArgPosition::Type
&& let Some(b) = gen_args.bindings.first()
@ -586,7 +582,7 @@ pub(crate) fn check_generic_arg_count(
};
let args_correct = {
let expected_min = if infer_args {
let expected_min = if seg.infer_args {
0
} else {
param_counts.consts + named_type_param_count

View File

@ -8,7 +8,7 @@
use super::AstConv;
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
impl<'tcx> dyn AstConv<'tcx> + '_ {
/// Make sure that we are in the condition to suggest the blanket implementation.
pub(super) fn maybe_lint_blanket_trait_impl<G: EmissionGuarantee>(
&self,

View File

@ -214,7 +214,7 @@ fn inferred_kind(
) -> ty::GenericArg<'tcx>;
}
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
impl<'tcx> dyn AstConv<'tcx> + '_ {
#[instrument(level = "debug", skip(self), ret)]
pub fn ast_region_to_region(
&self,
@ -284,8 +284,6 @@ pub fn ast_path_args_for_ty(
def_id,
&[],
item_segment,
item_segment.args(),
item_segment.infer_args,
None,
ty::BoundConstness::NotConst,
);
@ -330,14 +328,12 @@ pub fn ast_path_args_for_ty(
/// type itself: `['a]`. The returned `GenericArgsRef` concatenates these two
/// lists: `[Vec<u8>, u8, 'a]`.
#[instrument(level = "debug", skip(self, span), ret)]
fn create_args_for_ast_path<'a>(
fn create_args_for_ast_path(
&self,
span: Span,
def_id: DefId,
parent_args: &[ty::GenericArg<'tcx>],
seg: &hir::PathSegment<'_>,
generic_args: &'a hir::GenericArgs<'tcx>,
infer_args: bool,
segment: &hir::PathSegment<'tcx>,
self_ty: Option<Ty<'tcx>>,
constness: ty::BoundConstness,
) -> (GenericArgsRef<'tcx>, GenericArgCountResult) {
@ -365,12 +361,10 @@ fn create_args_for_ast_path<'a>(
let mut arg_count = check_generic_arg_count(
tcx,
def_id,
seg,
segment,
generics,
generic_args,
GenericArgPosition::Type,
self_ty.is_some(),
infer_args,
);
if let Err(err) = &arg_count.correct
@ -388,7 +382,7 @@ fn create_args_for_ast_path<'a>(
}
struct InstantiationsForAstPathCtxt<'a, 'tcx> {
astconv: &'a (dyn AstConv<'tcx> + 'a),
astconv: &'a dyn AstConv<'tcx>,
def_id: DefId,
generic_args: &'a GenericArgs<'tcx>,
span: Span,
@ -547,9 +541,9 @@ fn inferred_kind(
astconv: self,
def_id,
span,
generic_args,
generic_args: segment.args(),
inferred_params: vec![],
infer_args,
infer_args: segment.infer_args,
};
if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
&& generics.has_self
@ -592,8 +586,6 @@ pub fn create_args_for_associated_item(
item_def_id,
parent_args,
item_segment,
item_segment.args(),
item_segment.infer_args,
None,
ty::BoundConstness::NotConst,
);
@ -661,7 +653,6 @@ pub(crate) fn instantiate_poly_trait_ref(
) -> GenericArgCountResult {
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
let trait_segment = trait_ref.path.segments.last().unwrap();
let args = trait_segment.args();
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
@ -671,8 +662,6 @@ pub(crate) fn instantiate_poly_trait_ref(
trait_def_id,
&[],
trait_segment,
args,
trait_segment.infer_args,
Some(self_ty),
constness,
);
@ -690,7 +679,7 @@ pub(crate) fn instantiate_poly_trait_ref(
bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
let mut dup_bindings = FxIndexMap::default();
for binding in args.bindings {
for binding in trait_segment.args().bindings {
// Don't register additional associated type bounds for negative bounds,
// since we should have emitten an error for them earlier, and they will
// not be well-formed!
@ -729,12 +718,14 @@ fn ast_path_to_mono_trait_ref(
// FIXME(effects) move all host param things in astconv to hir lowering
constness: ty::BoundConstness,
) -> ty::TraitRef<'tcx> {
let (generic_args, _) = self.create_args_for_ast_trait_ref(
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
let (generic_args, _) = self.create_args_for_ast_path(
span,
trait_def_id,
self_ty,
&[],
trait_segment,
is_impl,
Some(self_ty),
constness,
);
if let Some(b) = trait_segment.args().bindings.first() {
@ -743,30 +734,6 @@ fn ast_path_to_mono_trait_ref(
ty::TraitRef::new(self.tcx(), trait_def_id, generic_args)
}
#[instrument(level = "debug", skip(self, span))]
fn create_args_for_ast_trait_ref<'a>(
&self,
span: Span,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
trait_segment: &'a hir::PathSegment<'tcx>,
is_impl: bool,
constness: ty::BoundConstness,
) -> (GenericArgsRef<'tcx>, GenericArgCountResult) {
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
self.create_args_for_ast_path(
span,
trait_def_id,
&[],
trait_segment,
trait_segment.args(),
trait_segment.infer_args,
Some(self_ty),
constness,
)
}
fn trait_defines_associated_item_named(
&self,
trait_def_id: DefId,
@ -801,115 +768,6 @@ fn ast_path_to_ty(
}
}
fn report_ambiguous_associated_type(
&self,
span: Span,
types: &[String],
traits: &[String],
name: Symbol,
) -> ErrorGuaranteed {
let mut err =
struct_span_code_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type");
if self
.tcx()
.resolutions(())
.confused_type_with_std_module
.keys()
.any(|full_span| full_span.contains(span))
{
err.span_suggestion_verbose(
span.shrink_to_lo(),
"you are looking for the module in `std`, not the primitive type",
"std::",
Applicability::MachineApplicable,
);
} else {
let mut types = types.to_vec();
types.sort();
let mut traits = traits.to_vec();
traits.sort();
match (&types[..], &traits[..]) {
([], []) => {
err.span_suggestion_verbose(
span,
format!(
"if there were a type named `Type` that implements a trait named \
`Trait` with associated type `{name}`, you could use the \
fully-qualified path",
),
format!("<Type as Trait>::{name}"),
Applicability::HasPlaceholders,
);
}
([], [trait_str]) => {
err.span_suggestion_verbose(
span,
format!(
"if there were a type named `Example` that implemented `{trait_str}`, \
you could use the fully-qualified path",
),
format!("<Example as {trait_str}>::{name}"),
Applicability::HasPlaceholders,
);
}
([], traits) => {
err.span_suggestions(
span,
format!(
"if there were a type named `Example` that implemented one of the \
traits with associated type `{name}`, you could use the \
fully-qualified path",
),
traits.iter().map(|trait_str| format!("<Example as {trait_str}>::{name}")),
Applicability::HasPlaceholders,
);
}
([type_str], []) => {
err.span_suggestion_verbose(
span,
format!(
"if there were a trait named `Example` with associated type `{name}` \
implemented for `{type_str}`, you could use the fully-qualified path",
),
format!("<{type_str} as Example>::{name}"),
Applicability::HasPlaceholders,
);
}
(types, []) => {
err.span_suggestions(
span,
format!(
"if there were a trait named `Example` with associated type `{name}` \
implemented for one of the types, you could use the fully-qualified \
path",
),
types
.into_iter()
.map(|type_str| format!("<{type_str} as Example>::{name}")),
Applicability::HasPlaceholders,
);
}
(types, traits) => {
let mut suggestions = vec![];
for type_str in types {
for trait_str in traits {
suggestions.push(format!("<{type_str} as {trait_str}>::{name}"));
}
}
err.span_suggestions(
span,
"use fully-qualified syntax",
suggestions,
Applicability::MachineApplicable,
);
}
}
}
let reported = err.emit();
self.set_tainted_by_errors(reported);
reported
}
// Search for a bound on a type parameter which includes the associated item
// given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter
// This function will fail if there are no suitable bounds or there is
@ -2471,8 +2329,6 @@ fn ast_ty_to_ty_inner(
def_id,
&[],
&hir::PathSegment::invalid(),
&GenericArgs::none(),
true,
None,
ty::BoundConstness::NotConst,
);
@ -2552,9 +2408,9 @@ fn impl_trait_ty_to_ty(
pub fn ty_of_arg(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
match ty.kind {
hir::TyKind::Infer if expected_ty.is_some() => {
self.record_ty(ty.hir_id, expected_ty.unwrap(), ty.span);
expected_ty.unwrap()
hir::TyKind::Infer if let Some(expected_ty) = expected_ty => {
self.record_ty(ty.hir_id, expected_ty, ty.span);
expected_ty
}
_ => self.ast_ty_to_ty(ty),
}

View File

@ -17,7 +17,7 @@
use super::AstConv;
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
impl<'tcx> dyn AstConv<'tcx> + '_ {
pub(super) fn conv_object_ty_poly_trait_ref(
&self,
span: Span,

View File

@ -108,8 +108,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
.unwrap()
.0
.def_id;
let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>;
let ty = item_ctxt.ast_ty_to_ty(hir_ty);
let ty = ItemCtxt::new(tcx, item_def_id).to_ty(hir_ty);
// Iterate through the generics of the projection to find the one that corresponds to
// the def_id that this query was called with. We filter to only type and const args here

View File

@ -100,19 +100,16 @@
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_middle::middle;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{Ty, TyCtxt};
use rustc_middle::util;
use rustc_session::parse::feature_err;
use rustc_span::{symbol::sym, Span, DUMMY_SP};
use rustc_span::{symbol::sym, Span};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use astconv::{AstConv, OnlySelfBounds};
use bounds::Bounds;
use rustc_hir::def::DefKind;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
@ -222,31 +219,5 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx>
// def-ID that will be used to determine the traits/predicates in
// scope. This is derived from the enclosing item-like thing.
let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id);
item_cx.astconv().ast_ty_to_ty(hir_ty)
}
pub fn hir_trait_to_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
hir_trait: &hir::TraitRef<'tcx>,
self_ty: Ty<'tcx>,
) -> Bounds<'tcx> {
// In case there are any projections, etc., find the "environment"
// def-ID that will be used to determine the traits/predicates in
// scope. This is derived from the enclosing item-like thing.
let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.def_id);
let mut bounds = Bounds::default();
let _ = &item_cx.astconv().instantiate_poly_trait_ref(
hir_trait,
DUMMY_SP,
ty::BoundConstness::NotConst,
ty::ImplPolarity::Positive,
self_ty,
&mut bounds,
true,
OnlySelfBounds(false),
);
bounds
collect::ItemCtxt::new(tcx, env_def_id.def_id).to_ty(hir_ty)
}

View File

@ -780,7 +780,7 @@ fn supplied_sig_of_closure(
decl: &hir::FnDecl<'tcx>,
closure_kind: hir::ClosureKind,
) -> ty::PolyFnSig<'tcx> {
let astconv: &dyn AstConv<'_> = self;
let astconv = self.astconv();
trace!("decl = {:#?}", decl);
debug!(?closure_kind);
@ -985,7 +985,7 @@ fn error_sig_of_closure(
decl: &hir::FnDecl<'tcx>,
guar: ErrorGuaranteed,
) -> ty::PolyFnSig<'tcx> {
let astconv: &dyn AstConv<'_> = self;
let astconv = self.astconv();
let err_ty = Ty::new_error(self.tcx, guar);
let supplied_arguments = decl.inputs.iter().map(|a| {