Skip to content

Commit 9811358

Browse files
authored
Rollup merge of #121221 - fmease:refactor-astconv-assoc-item-bindings, r=compiler-errors
AstConv: Refactor lowering of associated item bindings a bit Split off from #119385 as discussed, namely the first two commits (modulo one `FIXME` getting turned into a `NOTE`). The second commit removes `astconv::ConvertedBinding{,Kind}` in favor of `hir::TypeBinding{,Kind}`. The former was a — in my opinion — super useless intermediary. As you can tell from the diff, its removal shaves off some code. Furthermore, yeeting it will make it easier to implement the type resolution fixes in #119385. Nothing in this PR should have any semantic effect. r? `@compiler-errors` <sub>**Addendum** as in #118668: 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.</sub>
2 parents 8ba0ad0 + 38a2a65 commit 9811358

File tree

3 files changed

+125
-175
lines changed

3 files changed

+125
-175
lines changed

compiler/rustc_hir_analysis/src/astconv/bounds.rs

+83-81
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ use rustc_span::{ErrorGuaranteed, Span};
99
use rustc_trait_selection::traits;
1010
use smallvec::SmallVec;
1111

12-
use crate::astconv::{
13-
AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
14-
};
12+
use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
1513
use crate::bounds::Bounds;
1614
use crate::errors;
1715

@@ -238,7 +236,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
238236
&self,
239237
hir_ref_id: hir::HirId,
240238
trait_ref: ty::PolyTraitRef<'tcx>,
241-
binding: &ConvertedBinding<'_, 'tcx>,
239+
binding: &hir::TypeBinding<'tcx>,
242240
bounds: &mut Bounds<'tcx>,
243241
speculative: bool,
244242
dup_bindings: &mut FxIndexMap<DefId, Span>,
@@ -263,21 +261,20 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
263261

264262
let tcx = self.tcx();
265263

266-
let assoc_kind =
267-
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
268-
ty::AssocKind::Fn
269-
} else if let ConvertedBindingKind::Equality(term) = binding.kind
270-
&& let ty::TermKind::Const(_) = term.node.unpack()
271-
{
272-
ty::AssocKind::Const
273-
} else {
274-
ty::AssocKind::Type
275-
};
264+
let assoc_kind = if binding.gen_args.parenthesized
265+
== hir::GenericArgsParentheses::ReturnTypeNotation
266+
{
267+
ty::AssocKind::Fn
268+
} else if let hir::TypeBindingKind::Equality { term: hir::Term::Const(_) } = binding.kind {
269+
ty::AssocKind::Const
270+
} else {
271+
ty::AssocKind::Type
272+
};
276273

277274
let candidate = if self.trait_defines_associated_item_named(
278275
trait_ref.def_id(),
279276
assoc_kind,
280-
binding.item_name,
277+
binding.ident,
281278
) {
282279
// Simple case: The assoc item is defined in the current trait.
283280
trait_ref
@@ -289,14 +286,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
289286
trait_ref.skip_binder().print_only_trait_name(),
290287
None,
291288
assoc_kind,
292-
binding.item_name,
289+
binding.ident,
293290
path_span,
294-
Some(&binding),
291+
Some(binding),
295292
)?
296293
};
297294

298295
let (assoc_ident, def_scope) =
299-
tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
296+
tcx.adjust_ident_and_get_scope(binding.ident, candidate.def_id(), hir_ref_id);
300297

301298
// We have already adjusted the item name above, so compare with `.normalize_to_macros_2_0()`
302299
// instead of calling `filter_by_name_and_kind` which would needlessly normalize the
@@ -312,7 +309,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
312309
.dcx()
313310
.struct_span_err(
314311
binding.span,
315-
format!("{} `{}` is private", assoc_item.kind, binding.item_name),
312+
format!("{} `{}` is private", assoc_item.kind, binding.ident),
316313
)
317314
.with_span_label(binding.span, format!("private {}", assoc_item.kind))
318315
.emit();
@@ -327,7 +324,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
327324
tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
328325
span: binding.span,
329326
prev_span: *prev_span,
330-
item_name: binding.item_name,
327+
item_name: binding.ident,
331328
def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
332329
});
333330
})
@@ -390,14 +387,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
390387
{
391388
alias_ty
392389
} else {
393-
return Err(self.tcx().dcx().emit_err(
394-
crate::errors::ReturnTypeNotationOnNonRpitit {
395-
span: binding.span,
396-
ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
397-
fn_span: tcx.hir().span_if_local(assoc_item.def_id),
398-
note: (),
399-
},
400-
));
390+
return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
391+
span: binding.span,
392+
ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
393+
fn_span: tcx.hir().span_if_local(assoc_item.def_id),
394+
note: (),
395+
}));
401396
};
402397

403398
// Finally, move the fn return type's bound vars over to account for the early bound
@@ -410,9 +405,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
410405
let bound_vars = tcx.late_bound_vars(binding.hir_id);
411406
ty::Binder::bind_with_vars(instantiation_output, bound_vars)
412407
} else {
413-
// Append the generic arguments of the associated type to the `trait_ref`.
408+
// Create the generic arguments for the associated type or constant by joining the
409+
// parent arguments (the arguments of the trait) and the own arguments (the ones of
410+
// the associated item itself) and construct an alias type using them.
414411
candidate.map_bound(|trait_ref| {
415-
let ident = Ident::new(assoc_item.name, binding.item_name.span);
412+
let ident = Ident::new(assoc_item.name, binding.ident.span);
416413
let item_segment = hir::PathSegment {
417414
ident,
418415
hir_id: binding.hir_id,
@@ -421,77 +418,82 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
421418
infer_args: false,
422419
};
423420

424-
let args_trait_ref_and_assoc_item = self.create_args_for_associated_item(
421+
let alias_args = self.create_args_for_associated_item(
425422
path_span,
426423
assoc_item.def_id,
427424
&item_segment,
428425
trait_ref.args,
429426
);
427+
debug!(?alias_args);
430428

431-
debug!(?args_trait_ref_and_assoc_item);
432-
433-
ty::AliasTy::new(tcx, assoc_item.def_id, args_trait_ref_and_assoc_item)
429+
// Note that we're indeed also using `AliasTy` (alias *type*) for associated
430+
// *constants* to represent *const projections*. Alias *term* would be a more
431+
// appropriate name but alas.
432+
ty::AliasTy::new(tcx, assoc_item.def_id, alias_args)
434433
})
435434
};
436435

437-
if !speculative {
438-
// Find any late-bound regions declared in `ty` that are not
439-
// declared in the trait-ref or assoc_item. These are not well-formed.
440-
//
441-
// Example:
442-
//
443-
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
444-
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
445-
if let ConvertedBindingKind::Equality(ty) = binding.kind {
446-
let late_bound_in_trait_ref =
447-
tcx.collect_constrained_late_bound_regions(&projection_ty);
448-
let late_bound_in_ty =
449-
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty.node));
450-
debug!(?late_bound_in_trait_ref);
451-
debug!(?late_bound_in_ty);
452-
453-
// FIXME: point at the type params that don't have appropriate lifetimes:
454-
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
455-
// ---- ---- ^^^^^^^
456-
self.validate_late_bound_regions(
457-
late_bound_in_trait_ref,
458-
late_bound_in_ty,
459-
|br_name| {
460-
struct_span_code_err!(
461-
tcx.dcx(),
462-
binding.span,
463-
E0582,
464-
"binding for associated type `{}` references {}, \
465-
which does not appear in the trait input types",
466-
binding.item_name,
467-
br_name
468-
)
469-
},
470-
);
471-
}
472-
}
473-
474436
match binding.kind {
475-
ConvertedBindingKind::Equality(..) if let ty::AssocKind::Fn = assoc_kind => {
476-
return Err(self.tcx().dcx().emit_err(
477-
crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
478-
));
437+
hir::TypeBindingKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
438+
return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
439+
span: binding.span,
440+
}));
479441
}
480-
ConvertedBindingKind::Equality(term) => {
442+
hir::TypeBindingKind::Equality { term } => {
443+
let term = match term {
444+
hir::Term::Ty(ty) => self.ast_ty_to_ty(ty).into(),
445+
hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(),
446+
};
447+
448+
if !speculative {
449+
// Find any late-bound regions declared in `ty` that are not
450+
// declared in the trait-ref or assoc_item. These are not well-formed.
451+
//
452+
// Example:
453+
//
454+
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
455+
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
456+
let late_bound_in_projection_ty =
457+
tcx.collect_constrained_late_bound_regions(&projection_ty);
458+
let late_bound_in_term =
459+
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(term));
460+
debug!(?late_bound_in_projection_ty);
461+
debug!(?late_bound_in_term);
462+
463+
// FIXME: point at the type params that don't have appropriate lifetimes:
464+
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
465+
// ---- ---- ^^^^^^^
466+
// NOTE(associated_const_equality): This error should be impossible to trigger
467+
// with associated const equality bounds.
468+
self.validate_late_bound_regions(
469+
late_bound_in_projection_ty,
470+
late_bound_in_term,
471+
|br_name| {
472+
struct_span_code_err!(
473+
tcx.dcx(),
474+
binding.span,
475+
E0582,
476+
"binding for associated type `{}` references {}, \
477+
which does not appear in the trait input types",
478+
binding.ident,
479+
br_name
480+
)
481+
},
482+
);
483+
}
484+
481485
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
482486
// the "projection predicate" for:
483487
//
484488
// `<T as Iterator>::Item = u32`
485489
bounds.push_projection_bound(
486490
tcx,
487-
projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
488-
projection_ty,
489-
term: term.node,
490-
}),
491+
projection_ty
492+
.map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
491493
binding.span,
492494
);
493495
}
494-
ConvertedBindingKind::Constraint(ast_bounds) => {
496+
hir::TypeBindingKind::Constraint { bounds: ast_bounds } => {
495497
// "Desugar" a constraint like `T: Iterator<Item: Debug>` to
496498
//
497499
// `<T as Iterator>::Item: Debug`

compiler/rustc_hir_analysis/src/astconv/errors.rs

+25-20
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::astconv::{AstConv, ConvertedBindingKind};
1+
use crate::astconv::AstConv;
22
use crate::errors::{
33
self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
44
ParenthesizedFnTraitExpansion,
@@ -111,7 +111,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
111111
assoc_kind: ty::AssocKind,
112112
assoc_name: Ident,
113113
span: Span,
114-
binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
114+
binding: Option<&hir::TypeBinding<'tcx>>,
115115
) -> ErrorGuaranteed
116116
where
117117
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
@@ -243,7 +243,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
243243
None,
244244
) && suggested_name != assoc_name.name
245245
{
246-
// We suggested constraining a type parameter, but the associated type on it
246+
// We suggested constraining a type parameter, but the associated item on it
247247
// was also not an exact match, so we also suggest changing it.
248248
err.span_suggestion_verbose(
249249
assoc_name.span,
@@ -258,16 +258,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
258258
}
259259
}
260260

261-
// If we still couldn't find any associated type, and only one associated type exists,
261+
// If we still couldn't find any associated item, and only one associated item exists,
262262
// suggests using it.
263263
if let [candidate_name] = all_candidate_names.as_slice() {
264-
// this should still compile, except on `#![feature(associated_type_defaults)]`
265-
// where it could suggests `type A = Self::A`, thus recursing infinitely
266-
let applicability = if tcx.features().associated_type_defaults {
267-
Applicability::Unspecified
268-
} else {
269-
Applicability::MaybeIncorrect
270-
};
264+
// This should still compile, except on `#![feature(associated_type_defaults)]`
265+
// where it could suggests `type A = Self::A`, thus recursing infinitely.
266+
let applicability =
267+
if assoc_kind == ty::AssocKind::Type && tcx.features().associated_type_defaults {
268+
Applicability::Unspecified
269+
} else {
270+
Applicability::MaybeIncorrect
271+
};
271272

272273
err.sugg = Some(errors::AssocItemNotFoundSugg::Other {
273274
span: assoc_name.span,
@@ -289,13 +290,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
289290
assoc_kind: ty::AssocKind,
290291
ident: Ident,
291292
span: Span,
292-
binding: Option<&super::ConvertedBinding<'_, 'tcx>>,
293+
binding: Option<&hir::TypeBinding<'tcx>>,
293294
) -> ErrorGuaranteed {
294295
let tcx = self.tcx();
295296

296297
let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
297298
&& let Some(binding) = binding
298-
&& let ConvertedBindingKind::Constraint(_) = binding.kind
299+
&& let hir::TypeBindingKind::Constraint { .. } = binding.kind
299300
{
300301
let lo = if binding.gen_args.span_ext.is_dummy() {
301302
ident.span
@@ -309,25 +310,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
309310

310311
// FIXME(associated_const_equality): This has quite a few false positives and negatives.
311312
let wrap_in_braces_sugg = if let Some(binding) = binding
312-
&& let ConvertedBindingKind::Equality(term) = binding.kind
313-
&& let ty::TermKind::Ty(ty) = term.node.unpack()
313+
&& let hir::TypeBindingKind::Equality { term: hir::Term::Ty(hir_ty) } = binding.kind
314+
&& let ty = self.ast_ty_to_ty(hir_ty)
314315
&& (ty.is_enum() || ty.references_error())
315316
&& tcx.features().associated_const_equality
316317
{
317318
Some(errors::AssocKindMismatchWrapInBracesSugg {
318-
lo: term.span.shrink_to_lo(),
319-
hi: term.span.shrink_to_hi(),
319+
lo: hir_ty.span.shrink_to_lo(),
320+
hi: hir_ty.span.shrink_to_hi(),
320321
})
321322
} else {
322323
None
323324
};
324325

325326
// For equality bounds, we want to blame the term (RHS) instead of the item (LHS) since
326-
// one can argue that that's more “untuitive” to the user.
327+
// one can argue that that's more “intuitive” to the user.
327328
let (span, expected_because_label, expected, got) = if let Some(binding) = binding
328-
&& let ConvertedBindingKind::Equality(term) = binding.kind
329+
&& let hir::TypeBindingKind::Equality { term } = binding.kind
329330
{
330-
(term.span, Some(ident.span), assoc_item.kind, assoc_kind)
331+
let span = match term {
332+
hir::Term::Ty(ty) => ty.span,
333+
hir::Term::Const(ct) => tcx.def_span(ct.def_id),
334+
};
335+
(span, Some(ident.span), assoc_item.kind, assoc_kind)
331336
} else {
332337
(ident.span, None, assoc_kind, assoc_item.kind)
333338
};

0 commit comments

Comments
 (0)