|
1 |
| -use rustc_data_structures::fx::FxIndexMap; |
| 1 | +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; |
2 | 2 | use rustc_errors::{codes::*, struct_span_code_err};
|
3 | 3 | use rustc_hir as hir;
|
4 | 4 | use rustc_hir::def::{DefKind, Res};
|
5 | 5 | use rustc_hir::def_id::{DefId, LocalDefId};
|
6 |
| -use rustc_middle::ty::{self as ty, Ty}; |
| 6 | +use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; |
7 | 7 | use rustc_span::symbol::Ident;
|
8 | 8 | use rustc_span::{ErrorGuaranteed, Span};
|
9 | 9 | use rustc_trait_selection::traits;
|
| 10 | +use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; |
10 | 11 | use smallvec::SmallVec;
|
11 | 12 |
|
12 | 13 | use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
|
@@ -438,14 +439,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
438 | 439 | binding.kind
|
439 | 440 | {
|
440 | 441 | let ty = alias_ty.map_bound(|ty| tcx.type_of(ty.def_id).instantiate(tcx, ty.args));
|
441 |
| - // Since the arguments passed to the alias type above may contain early-bound |
442 |
| - // generic parameters, the instantiated type may contain some as well. |
443 |
| - // Therefore wrap it in `EarlyBinder`. |
444 |
| - // FIXME(fmease): Reject escaping late-bound vars. |
445 |
| - tcx.feed_anon_const_type( |
446 |
| - anon_const.def_id, |
447 |
| - ty::EarlyBinder::bind(ty.skip_binder()), |
448 |
| - ); |
| 442 | + let ty = check_assoc_const_binding_type(tcx, assoc_ident, ty, binding.hir_id); |
| 443 | + tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); |
449 | 444 | }
|
450 | 445 |
|
451 | 446 | alias_ty
|
@@ -537,3 +532,96 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
537 | 532 | Ok(())
|
538 | 533 | }
|
539 | 534 | }
|
| 535 | + |
| 536 | +/// Detect and reject early-bound generic params in the type of associated const bindings. |
| 537 | +/// |
| 538 | +/// FIXME(const_generics): This is a temporary and semi-artifical restriction until the |
| 539 | +/// arrival of *generic const generics*[^1]. |
| 540 | +/// |
| 541 | +/// It might actually be possible that we can already support early-bound generic params |
| 542 | +/// in such types if we just lifted some more checks in other places, too, for example |
| 543 | +/// inside [`ty::Const::from_anon_const`]. However, even if that were the case, we should |
| 544 | +/// probably gate this behind another feature flag. |
| 545 | +/// |
| 546 | +/// [^1]: <https://github.com/rust-lang/project-const-generics/issues/28>. |
| 547 | +fn check_assoc_const_binding_type<'tcx>( |
| 548 | + tcx: TyCtxt<'tcx>, |
| 549 | + assoc_const: Ident, |
| 550 | + ty: ty::Binder<'tcx, Ty<'tcx>>, |
| 551 | + hir_id: hir::HirId, |
| 552 | +) -> Ty<'tcx> { |
| 553 | + // We can't perform the checks for early-bound params during name resolution unlike E0770 |
| 554 | + // because this information depends on *type* resolution. |
| 555 | + |
| 556 | + // FIXME(fmease): Reject escaping late-bound vars. |
| 557 | + let ty = ty.skip_binder(); |
| 558 | + if !ty.has_param() { |
| 559 | + return ty; |
| 560 | + } |
| 561 | + |
| 562 | + let mut collector = GenericParamCollector { params: Default::default() }; |
| 563 | + ty.visit_with(&mut collector); |
| 564 | + |
| 565 | + let mut guar = None; |
| 566 | + let ty_note = ty |
| 567 | + .make_suggestable(tcx, false) |
| 568 | + .map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty }); |
| 569 | + |
| 570 | + let enclosing_item_owner_id = tcx |
| 571 | + .hir() |
| 572 | + .parent_owner_iter(hir_id) |
| 573 | + .find_map(|(owner_id, parent)| parent.generics().map(|_| owner_id)) |
| 574 | + .unwrap(); |
| 575 | + let generics = tcx.generics_of(enclosing_item_owner_id); |
| 576 | + for index in collector.params { |
| 577 | + let param = generics.param_at(index as _, tcx); |
| 578 | + let is_self_param = param.name == rustc_span::symbol::kw::SelfUpper; |
| 579 | + guar.get_or_insert(tcx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding { |
| 580 | + span: assoc_const.span, |
| 581 | + assoc_const, |
| 582 | + param_name: param.name, |
| 583 | + param_def_kind: tcx.def_descr(param.def_id), |
| 584 | + param_category: if is_self_param { |
| 585 | + "self" |
| 586 | + } else if param.kind.is_synthetic() { |
| 587 | + "synthetic" |
| 588 | + } else { |
| 589 | + "normal" |
| 590 | + }, |
| 591 | + param_defined_here_label: |
| 592 | + (!is_self_param).then(|| tcx.def_ident_span(param.def_id).unwrap()), |
| 593 | + ty_note, |
| 594 | + })); |
| 595 | + } |
| 596 | + |
| 597 | + let guar = guar.unwrap_or_else(|| bug!("failed to find gen params in ty")); |
| 598 | + Ty::new_error(tcx, guar) |
| 599 | +} |
| 600 | + |
| 601 | +struct GenericParamCollector { |
| 602 | + params: FxIndexSet<u32>, |
| 603 | +} |
| 604 | + |
| 605 | +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamCollector { |
| 606 | + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { |
| 607 | + if let ty::Param(param) = ty.kind() { |
| 608 | + self.params.insert(param.index); |
| 609 | + } else if ty.has_param() { |
| 610 | + ty.super_visit_with(self) |
| 611 | + } |
| 612 | + } |
| 613 | + |
| 614 | + fn visit_region(&mut self, re: ty::Region<'tcx>) -> Self::Result { |
| 615 | + if let ty::ReEarlyParam(param) = re.kind() { |
| 616 | + self.params.insert(param.index); |
| 617 | + } |
| 618 | + } |
| 619 | + |
| 620 | + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result { |
| 621 | + if let ty::ConstKind::Param(param) = ct.kind() { |
| 622 | + self.params.insert(param.index); |
| 623 | + } else if ct.has_param() { |
| 624 | + ct.super_visit_with(self) |
| 625 | + } |
| 626 | + } |
| 627 | +} |
0 commit comments