Change:
<ins> use crate::astconv::AstConv; use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty; use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, DUMMY_SP}; use std::collections::BTreeSet; impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// 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( &self, missing_type_params: Vec<String>, def_id: DefId, span: Span, empty_generic_args: bool, ) { if missing_type_params.is_empty() { return; } let display = missing_type_params.iter().map(|n| format!("`{}`", n)).collect::<Vec<_>>().join(", "); let mut err = struct_span_err!( self.tcx().sess, span, E0393, "the type parameter{} {} must be explicitly specified", pluralize!(missing_type_params.len()), display, ); err.span_label( self.tcx().def_span(def_id), &format!( "type parameter{} {} must be specified for this", pluralize!(missing_type_params.len()), display, ), ); let mut suggested = false; if let (Ok(snippet), true) = ( self.tcx().sess.source_map().span_to_snippet(span), // Don't suggest setting the type params if there are some already: the order is // tricky to get right and the user will already know what the syntax is. empty_generic_args, ) { if snippet.ends_with('>') { // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion // we would have to preserve the right order. For now, as clearly the user is // aware of the syntax, we do nothing. } else { // The user wrote `Iterator`, so we don't have a type we can suggest, but at // least we can clue them to the correct syntax `Iterator<Type>`. err.span_suggestion( span, &format!( "set the type parameter{plural} to the desired type{plural}", plural = pluralize!(missing_type_params.len()), ), format!("{}<{}>", snippet, missing_type_params.join(", ")), Applicability::HasPlaceholders, ); suggested = true; } } if !suggested { err.span_label( span, format!( "missing reference{} to {}", pluralize!(missing_type_params.len()), display, ), ); } err.note( "because of the default `Self` reference, type parameters must be  specified on object types", ); err.emit(); } /// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit /// an error and attempt to build a reasonable structured suggestion. pub(crate) fn complain_about_internal_fn_trait( &self, span: Span, trait_def_id: DefId, trait_segment: &'a hir::PathSegment<'a>, ) { let trait_def = self.tcx().trait_def(trait_def_id); if !self.tcx().features().unboxed_closures && trait_segment.generic_args().parenthesized != trait_def.paren_sugar { let sess = &self.tcx().sess.parse_sess; // For now, require that parenthetical notation be used only with `Fn()` etc. let (msg, sugg) = if trait_def.paren_sugar { ( "the precise format of `Fn`-family traits' type parameters is subject to  change", Some(format!( "{}{} -> {}", trait_segment.ident, trait_segment .args .as_ref() .and_then(|args| args.args.get(0)) .and_then(|arg| match arg { hir::GenericArg::Type(ty) => match ty.kind { hir::TyKind::Tup(t) => t .iter() .map(|e| sess.source_map().span_to_snippet(e.span)) .collect::<Result<Vec<_>, _>>() .map(|a| a.join(", ")), _ => sess.source_map().span_to_snippet(ty.span), } .map(|s| format!("({})", s)) .ok(), _ => None, }) .unwrap_or_else(|| "()".to_string()), trait_segment .generic_args() .bindings .iter() .find_map(|b| match (b.ident.name == sym::Output, &b.kind) { (true, hir::TypeBindingKind::Equality { ty }) => { sess.source_map().span_to_snippet(ty.span).ok() } _ => None, }) .unwrap_or_else(|| "()".to_string()), )), ) } else { ("parenthetical notation is only stable when used with `Fn`-family traits", None) }; let mut err = feature_err(sess, sym::unboxed_closures, span, msg); if let Some(sugg) = sugg { let msg = "use parenthetical notation instead"; err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect); } err.emit(); } } pub(crate) fn complain_about_assoc_type_not_found<I>( &self, all_candidates: impl Fn() -> I, ty_param_name: &str, assoc_name: Ident, span: Span, ) where I: Iterator<Item = ty::PolyTraitRef<'tcx>>, { // The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a // valid span, so we point at the whole path segment instead. let span = if assoc_name.span != DUMMY_SP { assoc_name.span } else { span }; let mut err = struct_span_err!( self.tcx().sess, span, E0220, "associated type `{}` not found for `{}`", assoc_name, ty_param_name ); let all_candidate_names: Vec<_> = all_candidates() .map(|r| self.tcx().associated_items(r.def_id()).in_definition_order()) .flatten() .filter_map( |item| if item.kind == ty::AssocKind::Type { Some(item.ident.name) } else { None }, ) .collect(); if let (Some(suggested_name), true) = ( find_best_match_for_name(all_candidate_names.iter(), assoc_name.name, None), assoc_name.span != DUMMY_SP, ) { err.span_suggestion( assoc_name.span, "there is an associated type with a similar name", suggested_name.to_string(), Applicability::MaybeIncorrect, ); } else { err.span_label(span, format!("associated type `{}` not found", assoc_name)); } err.emit(); } /// When there are any missing associated types, emit an E0191 error and attempt to supply a /// reasonable suggestion on how to write it. For the case of multiple associated types in the /// same trait bound have the same name (as they come from different super-traits), we instead /// emit a generic note suggesting using a `where` clause to constraint instead. pub(crate) fn complain_about_missing_associated_types( &self, associated_types: FxHashMap<Span, BTreeSet<DefId>>, potential_assoc_types: Vec<Span>, trait_bounds: &[hir::PolyTraitRef<'_>], ) { if associated_types.values().all(|v| v.is_empty()) { return; } let tcx = self.tcx(); // FIXME: Marked `mut` so that we can replace the spans further below with a more // appropriate one, but this should be handled earlier in the span assignment. let mut associated_types: FxHashMap<Span, Vec<_>> = associated_types .into_iter() .map(|(span, def_ids)| { (span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect()) }) .collect(); let mut names = vec![]; // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and // `issue-22560.rs`. let mut trait_bound_spans: Vec<Span> = vec![]; for (span, items) in &associated_types { if !items.is_empty() { trait_bound_spans.push(*span); } for assoc_item in items { let trait_def_id = assoc_item.container.id(); names.push(format!( "`{}` (from trait `{}`)", assoc_item.ident, tcx.def_path_str(trait_def_id), )); } } if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { match &bound.trait_ref.path.segments[..] { // FIXME: `trait_ref.path.span` can point to a full path with multiple // segments, even though `trait_ref.path.segments` is of length `1`. Work // around that bug here, even though it should be fixed elsewhere. // This would otherwise cause an invalid suggestion. For an example, look at // `src/test/ui/issues/issue-28344.rs` where instead of the following: // //   error[E0191]: the value of the associated type `Output` //                 (from trait `std::ops::BitXor`) must be specified //   --> $DIR/issue-28344.rs:4:17 //    | // LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8); //    |                 ^^^^^^ help: specify the associated type: //    |                              `BitXor<Output = Type>` // // we would output: // //   error[E0191]: the value of the associated type `Output` //                 (from trait `std::ops::BitXor`) must be specified //   --> $DIR/issue-28344.rs:4:17 //    | // LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8); //    |                 ^^^^^^^^^^^^^ help: specify the associated type: //    |                                     `BitXor::bitor<Output = Type>` [segment] if segment.args.is_none() => { trait_bound_spans = vec![segment.ident.span]; associated_types = associated_types .into_iter() .map(|(_, items)| (segment.ident.span, items)) .collect(); } _ => {} } } names.sort(); trait_bound_spans.sort(); let mut err = struct_span_err!( tcx.sess, trait_bound_spans, E0191, "the value of the associated type{} {} must be specified", pluralize!(names.len()), names.join(", "), ); let mut suggestions = vec![]; let mut types_count = 0; let mut where_constraints = vec![]; for (span, assoc_items) in &associated_types { let mut names: FxHashMap<_, usize> = FxHashMap::default(); for item in assoc_items { types_count += 1; *names.entry(item.ident.name).or_insert(0) += 1; } let mut dupes = false; for item in assoc_items { let prefix = if names[&item.ident.name] > 1 { let trait_def_id = item.container.id(); dupes = true; format!("{}::", tcx.def_path_str(trait_def_id)) } else { String::new() }; if let Some(sp) = tcx.hir().span_if_local(item.def_id) { err.span_label(sp, format!("`{}{}` defined here", prefix, item.ident)); } } if potential_assoc_types.len() == assoc_items.len() { // Only suggest when the amount of missing associated types equals the number of // extra type arguments present, as that gives us a relatively high confidence // that the user forgot to give the associtated type's name. The canonical // example would be trying to use `Iterator<isize>` instead of // `Iterator<Item = isize>`. for (potential, item) in potential_assoc_types.iter().zip(assoc_items.iter()) { if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) { suggestions.push((*potential, format!("{} = {}", item.ident, snippet))); } } } else if let (Ok(snippet), false) = (tcx.sess.source_map().span_to_snippet(*span), dupes) { let types: Vec<_> = assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect(); let code = if snippet.ends_with('>') { // The user wrote `Trait<'a>` or similar and we don't have a type we can // suggest, but at least we can clue them to the correct syntax // `Trait<'a, Item = Type>` while accounting for the `<'a>` in the // suggestion. format!("{}, {}>", &snippet[..snippet.len() - 1], types.join(", ")) } else { // The user wrote `Iterator`, so we don't have a type we can suggest, but at // least we can clue them to the correct syntax `Iterator<Item = Type>`. format!("{}<{}>", snippet, types.join(", ")) }; suggestions.push((*span, code)); } else if dupes { where_constraints.push(*span); } } let where_msg = "consider introducing a new type parameter, adding `where` constraints  using the fully-qualified path to the associated types"; if !where_constraints.is_empty() && suggestions.is_empty() { // If there are duplicates associated type names and a single trait bound do not // use structured suggestion, it means that there are multiple super-traits with // the same associated type name. err.help(where_msg); } if suggestions.len() != 1 { // We don't need this label if there's an inline suggestion, show otherwise. for (span, assoc_items) in &associated_types { let mut names: FxHashMap<_, usize> = FxHashMap::default(); for item in assoc_items { types_count += 1; *names.entry(item.ident.name).or_insert(0) += 1; } let mut label = vec![]; for item in assoc_items { let postfix = if names[&item.ident.name] > 1 { let trait_def_id = item.container.id(); format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id)) } else { String::new() }; label.push(format!("`{}`{}", item.ident, postfix)); } if !label.is_empty() { err.span_label( *span, format!( "associated type{} {} must be specified", pluralize!(label.len()), label.join(", "), ), ); } } } if !suggestions.is_empty() { err.multipart_suggestion( &format!("specify the associated type{}", pluralize!(types_count)), suggestions, Applicability::HasPlaceholders, ); if !where_constraints.is_empty() { err.span_help(where_constraints, where_msg); } } err.emit(); } } </ins>

Discussion:
That file () has almost 3k LOC and just 3 lines of documentation on the file (methods and types are documented though). I'm entirely unsure how to process that file. I think splitting it up into submodules (e.g. start by extracting out all functions just handling error reporting into a separate module). Some of this work can be just mechanical splitting up, but some parts may require you to start understanding at least some of what's going on in the file in order to find a good module structure. cc <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
I'll do it, although I am not familiar with the . At least the mechanical part is no problem. As to the model structure, I am going to dive into that issue so I can better think of a reasonable structure. If it is a problem that I am not familiar with the topic, I will back down, no worries.
That's awesome. Please wait until is merged though (you can subscribe to it so you see when it does get merged), because otherwise you'll just get loads of conflicts.
If you are unsure about the module structure, you can first post a design suggestion here if you want.
assign
You still working on this?
Not quite, my other PR is not yet through and I thought I wait for it. But if you want to do it, just take it. If not I'll be on it soon.
I would like to claim this, if nobody minds
assign It's all yours!
release-assignment
I'd like to work in this if is not on it anymore
generally it's fine if it's 3 months and there is no pr from the author. you can start working on it
Gotcha, thanks
claim