|
1 |
| -use rustc_data_structures::fx::FxIndexMap; |
| 1 | +use std::ops::ControlFlow; |
| 2 | + |
| 3 | +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; |
2 | 4 | use rustc_errors::{codes::*, struct_span_code_err};
|
3 | 5 | use rustc_hir as hir;
|
4 | 6 | use rustc_hir::def::{DefKind, Res};
|
5 | 7 | use rustc_hir::def_id::{DefId, LocalDefId};
|
6 |
| -use rustc_middle::ty::{self as ty, Ty}; |
| 8 | +use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; |
7 | 9 | use rustc_span::symbol::Ident;
|
8 |
| -use rustc_span::{ErrorGuaranteed, Span}; |
| 10 | +use rustc_span::{ErrorGuaranteed, Span, Symbol}; |
9 | 11 | use rustc_trait_selection::traits;
|
| 12 | +use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; |
10 | 13 | use smallvec::SmallVec;
|
11 | 14 |
|
12 | 15 | use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
|
@@ -433,14 +436,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
433 | 436 | binding.kind
|
434 | 437 | {
|
435 | 438 | let ty = alias_ty.map_bound(|ty| tcx.type_of(ty.def_id).instantiate(tcx, ty.args));
|
436 |
| - // Since the arguments passed to the alias type above may contain early-bound |
437 |
| - // generic parameters, the instantiated type may contain some as well. |
438 |
| - // Therefore wrap it in `EarlyBinder`. |
439 |
| - // FIXME(fmease): Reject escaping late-bound vars. |
440 |
| - tcx.feed_anon_const_type( |
441 |
| - anon_const.def_id, |
442 |
| - ty::EarlyBinder::bind(ty.skip_binder()), |
443 |
| - ); |
| 439 | + let ty = check_assoc_const_binding_type(tcx, assoc_ident, ty, binding.hir_id); |
| 440 | + tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); |
444 | 441 | }
|
445 | 442 |
|
446 | 443 | alias_ty
|
@@ -530,3 +527,167 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
|
530 | 527 | Ok(())
|
531 | 528 | }
|
532 | 529 | }
|
| 530 | + |
| 531 | +/// Detect and reject early-bound & escaping late-bound generic params in the type of assoc const bindings. |
| 532 | +/// |
| 533 | +/// FIXME(const_generics): This is a temporary and semi-artifical restriction until the |
| 534 | +/// arrival of *generic const generics*[^1]. |
| 535 | +/// |
| 536 | +/// It might actually be possible that we can already support early-bound generic params |
| 537 | +/// in such types if we just lifted some more checks in other places, too, for example |
| 538 | +/// inside [`ty::Const::from_anon_const`]. However, even if that were the case, we should |
| 539 | +/// probably gate this behind another feature flag. |
| 540 | +/// |
| 541 | +/// [^1]: <https://github.com/rust-lang/project-const-generics/issues/28>. |
| 542 | +fn check_assoc_const_binding_type<'tcx>( |
| 543 | + tcx: TyCtxt<'tcx>, |
| 544 | + assoc_const: Ident, |
| 545 | + ty: ty::Binder<'tcx, Ty<'tcx>>, |
| 546 | + hir_id: hir::HirId, |
| 547 | +) -> Ty<'tcx> { |
| 548 | + // We can't perform the checks for early-bound params during name resolution unlike E0770 |
| 549 | + // because this information depends on *type* resolution. |
| 550 | + // We can't perform these checks in `resolve_bound_vars` either for the same reason. |
| 551 | + // Consider the trait ref `for<'a> Trait<'a, C = { &0 }>`. We need to know the fully |
| 552 | + // resolved type of `Trait::C` in order to know if it references `'a` or not. |
| 553 | + |
| 554 | + let ty = ty.skip_binder(); |
| 555 | + if !ty.has_param() && !ty.has_escaping_bound_vars() { |
| 556 | + return ty; |
| 557 | + } |
| 558 | + |
| 559 | + let mut collector = GenericParamAndBoundVarCollector { |
| 560 | + tcx, |
| 561 | + params: Default::default(), |
| 562 | + vars: Default::default(), |
| 563 | + depth: ty::INNERMOST, |
| 564 | + }; |
| 565 | + let mut guar = ty.visit_with(&mut collector).break_value(); |
| 566 | + |
| 567 | + let ty_note = ty |
| 568 | + .make_suggestable(tcx, false) |
| 569 | + .map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty }); |
| 570 | + |
| 571 | + let enclosing_item_owner_id = tcx |
| 572 | + .hir() |
| 573 | + .parent_owner_iter(hir_id) |
| 574 | + .find_map(|(owner_id, parent)| parent.generics().map(|_| owner_id)) |
| 575 | + .unwrap(); |
| 576 | + let generics = tcx.generics_of(enclosing_item_owner_id); |
| 577 | + for index in collector.params { |
| 578 | + let param = generics.param_at(index as _, tcx); |
| 579 | + let is_self_param = param.name == rustc_span::symbol::kw::SelfUpper; |
| 580 | + guar.get_or_insert(tcx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding { |
| 581 | + span: assoc_const.span, |
| 582 | + assoc_const, |
| 583 | + param_name: param.name, |
| 584 | + param_def_kind: tcx.def_descr(param.def_id), |
| 585 | + param_category: if is_self_param { |
| 586 | + "self" |
| 587 | + } else if param.kind.is_synthetic() { |
| 588 | + "synthetic" |
| 589 | + } else { |
| 590 | + "normal" |
| 591 | + }, |
| 592 | + param_defined_here_label: |
| 593 | + (!is_self_param).then(|| tcx.def_ident_span(param.def_id).unwrap()), |
| 594 | + ty_note, |
| 595 | + })); |
| 596 | + } |
| 597 | + for (var_def_id, var_name) in collector.vars { |
| 598 | + guar.get_or_insert(tcx.dcx().emit_err( |
| 599 | + crate::errors::EscapingBoundVarInTyOfAssocConstBinding { |
| 600 | + span: assoc_const.span, |
| 601 | + assoc_const, |
| 602 | + var_name, |
| 603 | + var_def_kind: tcx.def_descr(var_def_id), |
| 604 | + var_defined_here_label: tcx.def_ident_span(var_def_id).unwrap(), |
| 605 | + ty_note, |
| 606 | + }, |
| 607 | + )); |
| 608 | + } |
| 609 | + |
| 610 | + let guar = guar.unwrap_or_else(|| bug!("failed to find gen params or bound vars in ty")); |
| 611 | + Ty::new_error(tcx, guar) |
| 612 | +} |
| 613 | + |
| 614 | +struct GenericParamAndBoundVarCollector<'tcx> { |
| 615 | + tcx: TyCtxt<'tcx>, |
| 616 | + params: FxIndexSet<u32>, |
| 617 | + vars: FxIndexSet<(DefId, Symbol)>, |
| 618 | + depth: ty::DebruijnIndex, |
| 619 | +} |
| 620 | + |
| 621 | +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx> { |
| 622 | + type Result = ControlFlow<ErrorGuaranteed>; |
| 623 | + |
| 624 | + fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( |
| 625 | + &mut self, |
| 626 | + binder: &ty::Binder<'tcx, T>, |
| 627 | + ) -> Self::Result { |
| 628 | + self.depth.shift_in(1); |
| 629 | + let result = binder.super_visit_with(self); |
| 630 | + self.depth.shift_out(1); |
| 631 | + result |
| 632 | + } |
| 633 | + |
| 634 | + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { |
| 635 | + match ty.kind() { |
| 636 | + ty::Param(param) => { |
| 637 | + self.params.insert(param.index); |
| 638 | + } |
| 639 | + ty::Bound(db, bt) if *db >= self.depth => { |
| 640 | + self.vars.insert(match bt.kind { |
| 641 | + ty::BoundTyKind::Param(def_id, name) => (def_id, name), |
| 642 | + ty::BoundTyKind::Anon => { |
| 643 | + let reported = self |
| 644 | + .tcx |
| 645 | + .dcx() |
| 646 | + .delayed_bug(format!("unexpected anon bound ty: {:?}", bt.var)); |
| 647 | + return ControlFlow::Break(reported); |
| 648 | + } |
| 649 | + }); |
| 650 | + } |
| 651 | + _ if ty.has_param() || ty.has_bound_vars() => return ty.super_visit_with(self), |
| 652 | + _ => {} |
| 653 | + } |
| 654 | + ControlFlow::Continue(()) |
| 655 | + } |
| 656 | + |
| 657 | + fn visit_region(&mut self, re: ty::Region<'tcx>) -> Self::Result { |
| 658 | + match re.kind() { |
| 659 | + ty::ReEarlyParam(param) => { |
| 660 | + self.params.insert(param.index); |
| 661 | + } |
| 662 | + ty::ReBound(db, br) if db >= self.depth => { |
| 663 | + self.vars.insert(match br.kind { |
| 664 | + ty::BrNamed(def_id, name) => (def_id, name), |
| 665 | + ty::BrAnon | ty::BrEnv => { |
| 666 | + let guar = self |
| 667 | + .tcx |
| 668 | + .dcx() |
| 669 | + .delayed_bug(format!("unexpected bound region kind: {:?}", br.kind)); |
| 670 | + return ControlFlow::Break(guar); |
| 671 | + } |
| 672 | + }); |
| 673 | + } |
| 674 | + _ => {} |
| 675 | + } |
| 676 | + ControlFlow::Continue(()) |
| 677 | + } |
| 678 | + |
| 679 | + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result { |
| 680 | + match ct.kind() { |
| 681 | + ty::ConstKind::Param(param) => { |
| 682 | + self.params.insert(param.index); |
| 683 | + } |
| 684 | + ty::ConstKind::Bound(db, ty::BoundVar { .. }) if db >= self.depth => { |
| 685 | + let guar = self.tcx.dcx().delayed_bug("unexpected escaping late-bound const var"); |
| 686 | + return ControlFlow::Break(guar); |
| 687 | + } |
| 688 | + _ if ct.has_param() || ct.has_bound_vars() => return ct.super_visit_with(self), |
| 689 | + _ => {} |
| 690 | + } |
| 691 | + ControlFlow::Continue(()) |
| 692 | + } |
| 693 | +} |
0 commit comments