Skip to content

Commit 5ea6256

Browse files
committed
Auto merge of #118668 - fmease:resolve-assoc-item-bindings-by-namespace, r=compiler-errors
Resolve associated item bindings by namespace This is the 3rd commit split off from #118360 with tests reblessed (they no longer contain duplicated diags which were caused by 4c0addc) & slightly adapted (removed supertraits from a UI test, cc #118040). > * Resolve all assoc item bindings (type, const, fn (feature `return_type_notation`)) by namespace instead of trying to resolve a type first (in the non-RTN case) and falling back to consts afterwards. This is consistent with RTN. E.g., for `Tr<K = {…}>` we now always try to look up assoc consts (this extends to supertrait bounds). This gets rid of assoc tys shadowing assoc consts in assoc item bindings which is undesirable & inconsistent (types and consts live in different namespaces after all) > * Consolidate the resolution of assoc {ty, const} bindings and RTN (dedup, better diags for RTN) > * Fix assoc consts being labeled as assoc *types* in several diagnostics > * Make a bunch of diagnostics translatable Fixes #112560 (error → pass). As discussed r? `@compiler-errors` --- **Addendum**: What I call “associated item bindings” are commonly referred to as “type bindings” for historical reasons. Nowadays, “type bindings” include assoc type bindings, assoc const bindings and RTN (return type notation) which is why I prefer not to use this outdated term.
2 parents 8043f62 + 55559d9 commit 5ea6256

27 files changed

+598
-416
lines changed

compiler/rustc_hir_analysis/messages.ftl

+22-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
1+
hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_name}` in bounds of `{$ty_param_name}`
2+
.label = ambiguous associated {$assoc_kind} `{$assoc_name}`
3+
14
hir_analysis_ambiguous_lifetime_bound =
25
ambiguous lifetime bound, explicit lifetime bound required
36
4-
hir_analysis_assoc_bound_on_const = expected associated type, found {$descr}
5-
.note = trait bounds not allowed on {$descr}
7+
hir_analysis_assoc_item_not_found = associated {$assoc_kind} `{$assoc_name}` not found for `{$ty_param_name}`
8+
9+
hir_analysis_assoc_item_not_found_found_in_other_trait_label = there is {$identically_named ->
10+
[true] an
11+
*[false] a similarly named
12+
} associated {$assoc_kind} `{$suggested_name}` in the trait `{$trait_name}`
13+
hir_analysis_assoc_item_not_found_label = associated {$assoc_kind} `{$assoc_name}` not found
14+
hir_analysis_assoc_item_not_found_other_sugg = `{$ty_param_name}` has the following associated {$assoc_kind}
15+
hir_analysis_assoc_item_not_found_similar_in_other_trait_sugg = change the associated {$assoc_kind} name to use `{$suggested_name}` from `{$trait_name}`
16+
hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg = and also change the associated {$assoc_kind} name
17+
hir_analysis_assoc_item_not_found_similar_sugg = there is an associated {$assoc_kind} with a similar name
18+
19+
hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got}
20+
.label = unexpected {$got}
21+
.expected_because_label = expected a {$expected} because of this associated {$expected}
22+
.note = the associated {$assoc_kind} is defined here
23+
.bound_on_assoc_const_label = bounds are not allowed on associated constants
24+
25+
hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here
626
727
hir_analysis_assoc_type_binding_not_allowed =
828
associated type bindings are not allowed here
@@ -280,10 +300,6 @@ hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is no
280300
281301
hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}`
282302
283-
hir_analysis_return_type_notation_conflicting_bound =
284-
ambiguous associated function `{$assoc_name}` for `{$ty_name}`
285-
.note = `{$assoc_name}` is declared in two supertraits: `{$first_bound}` and `{$second_bound}`
286-
287303
hir_analysis_return_type_notation_equality_bound =
288304
return type notation is not allowed to use type equality
289305
@@ -294,9 +310,6 @@ hir_analysis_return_type_notation_illegal_param_type =
294310
return type notation is not allowed for functions that have type parameters
295311
.label = type parameter declared here
296312
297-
hir_analysis_return_type_notation_missing_method =
298-
cannot find associated function `{$assoc_name}` for `{$ty_name}`
299-
300313
hir_analysis_return_type_notation_on_non_rpitit =
301314
return type notation used on function that is not `async` and does not return `impl Trait`
302315
.note = function returns `{$ty}`, which is not compatible with associated type return bounds

compiler/rustc_hir_analysis/src/astconv/bounds.rs

+34-100
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ use rustc_errors::struct_span_err;
33
use rustc_hir as hir;
44
use rustc_hir::def::{DefKind, Res};
55
use rustc_hir::def_id::{DefId, LocalDefId};
6-
use rustc_lint_defs::Applicability;
7-
use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
6+
use rustc_middle::ty::{self as ty, Ty};
87
use rustc_span::symbol::Ident;
98
use rustc_span::{ErrorGuaranteed, Span};
109
use rustc_trait_selection::traits;
@@ -256,64 +255,49 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
256255

257256
let tcx = self.tcx();
258257

259-
let return_type_notation =
260-
binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation;
261-
262-
let candidate = if return_type_notation {
263-
if self.trait_defines_associated_item_named(
264-
trait_ref.def_id(),
265-
ty::AssocKind::Fn,
266-
binding.item_name,
267-
) {
268-
trait_ref
258+
let assoc_kind =
259+
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
260+
ty::AssocKind::Fn
261+
} else if let ConvertedBindingKind::Equality(term) = binding.kind
262+
&& let ty::TermKind::Const(_) = term.node.unpack()
263+
{
264+
ty::AssocKind::Const
269265
} else {
270-
self.one_bound_for_assoc_method(
271-
traits::supertraits(tcx, trait_ref),
272-
trait_ref.print_only_trait_path(),
273-
binding.item_name,
274-
path_span,
275-
)?
276-
}
277-
} else if self.trait_defines_associated_item_named(
266+
ty::AssocKind::Type
267+
};
268+
269+
let candidate = if self.trait_defines_associated_item_named(
278270
trait_ref.def_id(),
279-
ty::AssocKind::Type,
271+
assoc_kind,
280272
binding.item_name,
281273
) {
282-
// Simple case: X is defined in the current trait.
274+
// Simple case: The assoc item is defined in the current trait.
283275
trait_ref
284276
} else {
285277
// Otherwise, we have to walk through the supertraits to find
286-
// those that do.
287-
self.one_bound_for_assoc_type(
278+
// one that does define it.
279+
self.one_bound_for_assoc_item(
288280
|| traits::supertraits(tcx, trait_ref),
289281
trait_ref.skip_binder().print_only_trait_name(),
290282
None,
283+
assoc_kind,
291284
binding.item_name,
292285
path_span,
293-
match binding.kind {
294-
ConvertedBindingKind::Equality(term) => Some(term),
295-
_ => None,
296-
},
286+
Some(&binding),
297287
)?
298288
};
299289

300290
let (assoc_ident, def_scope) =
301291
tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
302292

303-
// We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
304-
// of calling `filter_by_name_and_kind`.
305-
let find_item_of_kind = |kind| {
306-
tcx.associated_items(candidate.def_id())
307-
.filter_by_name_unhygienic(assoc_ident.name)
308-
.find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
309-
};
310-
let assoc_item = if return_type_notation {
311-
find_item_of_kind(ty::AssocKind::Fn)
312-
} else {
313-
find_item_of_kind(ty::AssocKind::Type)
314-
.or_else(|| find_item_of_kind(ty::AssocKind::Const))
315-
}
316-
.expect("missing associated type");
293+
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
294+
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the
295+
// `assoc_ident` again and again.
296+
let assoc_item = tcx
297+
.associated_items(candidate.def_id())
298+
.filter_by_name_unhygienic(assoc_ident.name)
299+
.find(|i| i.kind == assoc_kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
300+
.expect("missing associated item");
317301

318302
if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
319303
tcx.sess
@@ -340,7 +324,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
340324
.or_insert(binding.span);
341325
}
342326

343-
let projection_ty = if return_type_notation {
327+
let projection_ty = if let ty::AssocKind::Fn = assoc_kind {
344328
let mut emitted_bad_param_err = false;
345329
// If we have an method return type bound, then we need to substitute
346330
// the method's early bound params with suitable late-bound params.
@@ -467,7 +451,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
467451
let late_bound_in_trait_ref =
468452
tcx.collect_constrained_late_bound_regions(&projection_ty);
469453
let late_bound_in_ty =
470-
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
454+
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty.node));
471455
debug!(?late_bound_in_trait_ref);
472456
debug!(?late_bound_in_ty);
473457

@@ -492,77 +476,27 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
492476
}
493477
}
494478

495-
let assoc_item_def_id = projection_ty.skip_binder().def_id;
496-
let def_kind = tcx.def_kind(assoc_item_def_id);
497479
match binding.kind {
498-
ConvertedBindingKind::Equality(..) if return_type_notation => {
480+
ConvertedBindingKind::Equality(..) if let ty::AssocKind::Fn = assoc_kind => {
499481
return Err(self.tcx().sess.emit_err(
500482
crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
501483
));
502484
}
503-
ConvertedBindingKind::Equality(mut term) => {
485+
ConvertedBindingKind::Equality(term) => {
504486
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
505487
// the "projection predicate" for:
506488
//
507489
// `<T as Iterator>::Item = u32`
508-
match (def_kind, term.unpack()) {
509-
(DefKind::AssocTy, ty::TermKind::Ty(_))
510-
| (DefKind::AssocConst, ty::TermKind::Const(_)) => (),
511-
(_, _) => {
512-
let got = if let Some(_) = term.ty() { "type" } else { "constant" };
513-
let expected = tcx.def_descr(assoc_item_def_id);
514-
let mut err = tcx.sess.struct_span_err(
515-
binding.span,
516-
format!("expected {expected} bound, found {got}"),
517-
);
518-
err.span_note(
519-
tcx.def_span(assoc_item_def_id),
520-
format!("{expected} defined here"),
521-
);
522-
523-
if let DefKind::AssocConst = def_kind
524-
&& let Some(t) = term.ty()
525-
&& (t.is_enum() || t.references_error())
526-
&& tcx.features().associated_const_equality
527-
{
528-
err.span_suggestion(
529-
binding.span,
530-
"if equating a const, try wrapping with braces",
531-
format!("{} = {{ const }}", binding.item_name),
532-
Applicability::HasPlaceholders,
533-
);
534-
}
535-
let reported = err.emit();
536-
term = match def_kind {
537-
DefKind::AssocTy => Ty::new_error(tcx, reported).into(),
538-
DefKind::AssocConst => ty::Const::new_error(
539-
tcx,
540-
reported,
541-
tcx.type_of(assoc_item_def_id)
542-
.instantiate(tcx, projection_ty.skip_binder().args),
543-
)
544-
.into(),
545-
_ => unreachable!(),
546-
};
547-
}
548-
}
549490
bounds.push_projection_bound(
550491
tcx,
551-
projection_ty
552-
.map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
492+
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
493+
projection_ty,
494+
term: term.node,
495+
}),
553496
binding.span,
554497
);
555498
}
556499
ConvertedBindingKind::Constraint(ast_bounds) => {
557-
match def_kind {
558-
DefKind::AssocTy => {}
559-
_ => {
560-
return Err(tcx.sess.emit_err(errors::AssocBoundOnConst {
561-
span: assoc_ident.span,
562-
descr: tcx.def_descr(assoc_item_def_id),
563-
}));
564-
}
565-
}
566500
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
567501
//
568502
// `<T as Iterator>::Item: Debug`

0 commit comments

Comments
 (0)