Repository: rust-lang/rust
File: compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs (Rust)

Code before:
    is_self_alias: bool,
}

impl<'tcx> ForbidMCGParamUsesFolder<'tcx> {
    fn error(&self) -> ErrorGuaranteed {
        let msg = if self.is_self_alias {
            "generic `Self` types are currently not permitted in anonymous constants"
        } else {
            "generic parameters may not be used in const operations"
        };
        let mut diag = self.tcx.dcx().struct_span_err(self.span, msg);
        if self.is_self_alias {
            let anon_const_hir_id: HirId = HirId::make_owner(self.anon_const_def_id);
            let parent_impl = self.tcx.hir_parent_owner_iter(anon_const_hir_id).find_map(
                |(_, node)| match node {
                    hir::OwnerNode::Item(hir::Item {
                        kind: hir::ItemKind::Impl(impl_), ..
                    }) => Some(impl_),
                    _ => None,
                },
            );
            if let Some(impl_) = parent_impl {
                diag.span_note(impl_.self_ty.span, "not a concrete type");
            }
        }
        if !self.tcx.features().opaque_generic_const_args() {
            diag.help("add `#![feature(opaque_generic_const_args)]` to allow generic expressions as the RHS of const items");
        }
        diag.emit()
    }
}

impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for ForbidMCGParamUsesFolder<'tcx> {
    fn cx(&self) -> TyCtxt<'tcx> {
        self.tcx
    }

    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
        if matches!(t.kind(), ty::Param(..)) {
            return Ty::new_error(self.tcx, self.error());
        }
        t.super_fold_with(self)
    }

    fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> {
        if matches!(c.kind(), ty::ConstKind::Param(..)) {
            return Const::new_error(self.tcx, self.error());
        }
        c.super_fold_with(self)
    }


Review comment (suggestion):
in theory this means we'll suggest the feature gate on stable right? as we use this codepath also for forbidding uses of generic parameters on stable for cases that nameres cant catch

Code after:
        }
        diag.emit()
    }
}

impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for ForbidMCGParamUsesFolder<'tcx> {
    fn cx(&self) -> TyCtxt<'tcx> {
        self.tcx
    }

    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
        if matches!(t.kind(), ty::Param(..)) {
            return Ty::new_error(self.tcx, self.error());
        }
        t.super_fold_with(self)
    }

    fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> {
        if matches!(c.kind(), ty::ConstKind::Param(..)) {
            return Const::new_error(self.tcx, self.error());
        }
        c.super_fold_with(self)
    }

    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
        if matches!(r.kind(), ty::RegionKind::ReEarlyParam(..) | ty::RegionKind::ReLateParam(..)) {
            return ty::Region::new_error(self.tcx, self.error());
        }
        r
    }
}

impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
    /// See `check_param_uses_if_mcg`.
    ///
    /// FIXME(mgca): this is pub only for instantiate_value_path and would be nice to avoid altogether
    pub fn check_param_res_if_mcg_for_instantiate_value_path(
        &self,
        res: Res,
        span: Span,
    ) -> Result<(), ErrorGuaranteed> {
        let tcx = self.tcx();
        let parent_def_id = self.item_def_id();
        if let Res::Def(DefKind::ConstParam, _) = res
            && tcx.def_kind(parent_def_id) == DefKind::AnonConst
            && let ty::AnonConstKind::MCG = tcx.anon_const_kind(parent_def_id)
        {
            let folder = ForbidMCGParamUsesFolder {
                tcx,
                anon_const_def_id: parent_def_id,
                span,