Skip to content

Commit 245f62e

Browse files
committed
Cleanup: move code to their own methods and deduplicate actions
1 parent 80adfd8 commit 245f62e

File tree

2 files changed

+47
-29
lines changed

2 files changed

+47
-29
lines changed

src/librustc_typeck/astconv.rs

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
814814
}
815815
}
816816

817+
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
818+
/// the type parameter's name as a placeholder.
817819
fn complain_about_missing_type_params(
818820
&self,
819821
missing_type_params: Vec<String>,
@@ -1010,15 +1012,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
10101012
ty::TraitRef::new(trait_def_id, substs)
10111013
}
10121014

1013-
fn create_substs_for_ast_trait_ref<'a>(
1015+
/// When the code is using the `Fn` traits directly, instead of the `Fn(A) -> B` syntax, emit
1016+
/// an error and attempt to build a reasonable structured suggestion.
1017+
fn complain_about_internal_fn_trait(
10141018
&self,
10151019
span: Span,
10161020
trait_def_id: DefId,
1017-
self_ty: Ty<'tcx>,
10181021
trait_segment: &'a hir::PathSegment,
1019-
) -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'a, 'tcx>>, Option<Vec<Span>>) {
1020-
debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment);
1021-
1022+
) {
10221023
let trait_def = self.tcx().trait_def(trait_def_id);
10231024

10241025
if !self.tcx().features().unboxed_closures
@@ -1068,6 +1069,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
10681069
}
10691070
err.emit();
10701071
}
1072+
}
1073+
1074+
fn create_substs_for_ast_trait_ref<'a>(
1075+
&self,
1076+
span: Span,
1077+
trait_def_id: DefId,
1078+
self_ty: Ty<'tcx>,
1079+
trait_segment: &'a hir::PathSegment,
1080+
) -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'a, 'tcx>>, Option<Vec<Span>>) {
1081+
debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment);
1082+
1083+
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
10711084

10721085
self.create_substs_for_ast_path(
10731086
span,
@@ -1452,8 +1465,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
14521465
.filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
14531466

14541467
for (base_trait_ref, span) in regular_traits_refs_spans {
1455-
debug!("conv_object_ty_poly_trait_ref regular_trait_ref `{:?}`", base_trait_ref);
1456-
let mut new_bounds = vec![];
14571468
for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) {
14581469
debug!(
14591470
"conv_object_ty_poly_trait_ref: observing object predicate `{:?}`",
@@ -1486,17 +1497,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
14861497
// but actually supporting that would "expand" to an infinitely-long type
14871498
// `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
14881499
//
1489-
// Instead, we force the user to write `dyn MyTrait<MyOutput = X, Output = X>`,
1490-
// which is uglier but works. See the discussion in #56288 for alternatives.
1500+
// Instead, we force the user to write
1501+
// `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
1502+
// the discussion in #56288 for alternatives.
14911503
if !references_self {
14921504
// Include projections defined on supertraits.
1493-
new_bounds.push((pred, span));
1505+
bounds.projection_bounds.push((pred, span));
14941506
}
14951507
}
14961508
_ => (),
14971509
}
14981510
}
1499-
bounds.projection_bounds.extend(new_bounds);
15001511
}
15011512

15021513
for (projection_bound, _) in &bounds.projection_bounds {
@@ -1598,27 +1609,38 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
15981609
ty
15991610
}
16001611

1612+
/// When there are any missing associated types, emit an E0191 error and attempt to supply a
1613+
/// reasonable suggestion on how to write it. For the case of multiple associated types in the
1614+
/// same trait bound have the same name (as they come from different super-traits), we instead
1615+
/// emit a generic note suggesting using a `where` clause to constraint instead.
16011616
fn complain_about_missing_associated_types(
16021617
&self,
1603-
mut associated_types: FxHashMap<Span, BTreeSet<DefId>>,
1618+
associated_types: FxHashMap<Span, BTreeSet<DefId>>,
16041619
potential_assoc_types: Vec<Span>,
16051620
trait_bounds: &[hir::PolyTraitRef],
16061621
) {
16071622
if !associated_types.values().any(|v| v.len() > 0) {
16081623
return;
16091624
}
16101625
let tcx = self.tcx();
1626+
// FIXME: Marked `mut` so that we can replace the spans further below with a more
1627+
// appropriate one, but this should be handled earlier in the span assignment.
1628+
let mut associated_types: FxHashMap<Span, Vec<_>> = associated_types
1629+
.into_iter()
1630+
.map(|(span, def_ids)| {
1631+
(span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
1632+
})
1633+
.collect();
16111634
let mut names = vec![];
16121635

16131636
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
16141637
// `issue-22560.rs`.
16151638
let mut trait_bound_spans: Vec<Span> = vec![];
1616-
for (span, item_def_ids) in &associated_types {
1617-
if !item_def_ids.is_empty() {
1639+
for (span, items) in &associated_types {
1640+
if !items.is_empty() {
16181641
trait_bound_spans.push(*span);
16191642
}
1620-
for item_def_id in item_def_ids {
1621-
let assoc_item = tcx.associated_item(*item_def_id);
1643+
for assoc_item in items {
16221644
let trait_def_id = assoc_item.container.id();
16231645
names.push(format!(
16241646
"`{}` (from trait `{}`)",
@@ -1657,7 +1679,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16571679
trait_bound_spans = vec![segment.ident.span];
16581680
associated_types = associated_types
16591681
.into_iter()
1660-
.map(|(_, defs)| (segment.ident.span, defs))
1682+
.map(|(_, items)| (segment.ident.span, items))
16611683
.collect();
16621684
}
16631685
_ => {}
@@ -1675,16 +1697,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16751697
let mut suggestions = vec![];
16761698
let mut types_count = 0;
16771699
let mut where_constraints = vec![];
1678-
for (span, def_ids) in &associated_types {
1679-
let assoc_items: Vec<_> =
1680-
def_ids.iter().map(|def_id| tcx.associated_item(*def_id)).collect();
1700+
for (span, assoc_items) in &associated_types {
16811701
let mut names: FxHashMap<_, usize> = FxHashMap::default();
1682-
for item in &assoc_items {
1702+
for item in assoc_items {
16831703
types_count += 1;
16841704
*names.entry(item.ident.name).or_insert(0) += 1;
16851705
}
16861706
let mut dupes = false;
1687-
for item in &assoc_items {
1707+
for item in assoc_items {
16881708
let prefix = if names[&item.ident.name] > 1 {
16891709
let trait_def_id = item.container.id();
16901710
dupes = true;
@@ -1738,16 +1758,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
17381758
}
17391759
if suggestions.len() != 1 {
17401760
// We don't need this label if there's an inline suggestion, show otherwise.
1741-
for (span, def_ids) in &associated_types {
1742-
let assoc_items: Vec<_> =
1743-
def_ids.iter().map(|def_id| tcx.associated_item(*def_id)).collect();
1761+
for (span, assoc_items) in &associated_types {
17441762
let mut names: FxHashMap<_, usize> = FxHashMap::default();
1745-
for item in &assoc_items {
1763+
for item in assoc_items {
17461764
types_count += 1;
17471765
*names.entry(item.ident.name).or_insert(0) += 1;
17481766
}
17491767
let mut label = vec![];
1750-
for item in &assoc_items {
1768+
for item in assoc_items {
17511769
let postfix = if names[&item.ident.name] > 1 {
17521770
let trait_def_id = item.container.id();
17531771
format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))

src/test/ui/associated-types/missing-associated-types.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ LL | type Bar<Rhs> = dyn Add<Rhs> + Sub<Rhs> + X<Rhs> + Z<Rhs>;
3838
| first non-auto trait
3939
| trait alias used in trait object type (first use)
4040

41-
error[E0191]: the value of the associated types `Output` (from trait `std::ops::Add`), `Output` (from trait `std::ops::Sub`), `A` (from trait `Z`), `B` (from trait `Z`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified
42-
--> $DIR/missing-associated-types.rs:15:21
41+
error[E0191]: the value of the associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Sub`), `A` (from trait `Z`), `B` (from trait `Z`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Add`) must be specified
42+
--> $DIR/missing-associated-types.rs:15:43
4343
|
4444
LL | type A;
4545
| ------- `A` defined here

0 commit comments

Comments
 (0)