| use std::fmt::Write; |
| |
| use rustc_hir::def::DefKind; |
| use rustc_hir::def_id::LocalDefId; |
| use rustc_hir::find_attr; |
| use rustc_middle::ty::{GenericArgs, TyCtxt}; |
| |
| fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String { |
| let variances = tcx.variances_of(def_id); |
| let generics = GenericArgs::identity_for_item(tcx, def_id); |
| // 7 = 2-letter parameter + ": " + 1-letter variance + ", " |
| let mut ret = String::with_capacity(2 + 7 * variances.len()); |
| ret.push('['); |
| for (arg, variance) in generics.iter().zip(variances.iter()) { |
| write!(ret, "{arg}: {variance:?}, ").unwrap(); |
| } |
| // Remove trailing `, `. |
| if !variances.is_empty() { |
| ret.pop(); |
| ret.pop(); |
| } |
| ret.push(']'); |
| ret |
| } |
| |
| pub(crate) fn variances(tcx: TyCtxt<'_>) { |
| let crate_items = tcx.hir_crate_items(()); |
| |
| if find_attr!(tcx, crate, RustcDumpVariancesOfOpaques) { |
| for id in crate_items.opaques() { |
| tcx.dcx().span_err(tcx.def_span(id), format_variances(tcx, id)); |
| } |
| } |
| |
| for id in crate_items.owners() { |
| if !find_attr!(tcx, id, RustcDumpVariances) { |
| continue; |
| } |
| |
| match tcx.def_kind(id) { |
| DefKind::AssocFn | DefKind::Fn | DefKind::Enum | DefKind::Struct | DefKind::Union => {} |
| DefKind::TyAlias if tcx.type_alias_is_lazy(id) => {} |
| kind => { |
| let message = format!( |
| "attr parsing didn't report an error for `#[{}]` on {kind:?}", |
| rustc_span::sym::rustc_dump_variances, |
| ); |
| tcx.dcx().span_delayed_bug(tcx.def_span(id), message); |
| continue; |
| } |
| } |
| |
| tcx.dcx().span_err(tcx.def_span(id), format_variances(tcx, id.def_id)); |
| } |
| } |