rustc_trait_selection/
opaque_types.rs
1use rustc_data_structures::fx::FxIndexMap;
2use rustc_hir::OpaqueTyOrigin;
3use rustc_hir::def_id::LocalDefId;
4use rustc_infer::infer::outlives::env::OutlivesEnvironment;
5use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
6use rustc_middle::ty::{
7 self, DefiningScopeKind, GenericArgKind, GenericArgs, OpaqueTypeKey, TyCtxt, TypeVisitableExt,
8 TypingMode, fold_regions,
9};
10use rustc_span::{ErrorGuaranteed, Span};
11
12use crate::errors::NonGenericOpaqueTypeParam;
13use crate::regions::OutlivesEnvironmentBuildExt;
14use crate::traits::ObligationCtxt;
15
16pub fn check_opaque_type_parameter_valid<'tcx>(
21 infcx: &InferCtxt<'tcx>,
22 opaque_type_key: OpaqueTypeKey<'tcx>,
23 span: Span,
24 defining_scope_kind: DefiningScopeKind,
25) -> Result<(), ErrorGuaranteed> {
26 let tcx = infcx.tcx;
27 let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
28 let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
29 let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
30
31 if let DefiningScopeKind::MirBorrowck = defining_scope_kind {
34 if let Err(guar) = infcx
35 .tcx
36 .type_of_opaque_hir_typeck(opaque_type_key.def_id)
37 .instantiate_identity()
38 .error_reported()
39 {
40 return Err(guar);
41 }
42 }
43
44 for (i, arg) in opaque_type_key.iter_captured_args(tcx) {
45 let arg_is_param = match arg.unpack() {
46 GenericArgKind::Lifetime(lt) => match defining_scope_kind {
47 DefiningScopeKind::HirTypeck => continue,
48 DefiningScopeKind::MirBorrowck => {
49 matches!(lt.kind(), ty::ReEarlyParam(_) | ty::ReLateParam(_))
50 || (lt.is_static() && opaque_env.param_equal_static(i))
51 }
52 },
53 GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
54 GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
55 };
56
57 if arg_is_param {
58 let seen_where = seen_params.entry(arg).or_default();
62 if !seen_where.first().is_some_and(|&prev_i| opaque_env.params_equal(i, prev_i)) {
63 seen_where.push(i);
64 }
65 } else {
66 let opaque_param = opaque_generics.param_at(i, tcx);
68 let kind = opaque_param.kind.descr();
69
70 opaque_env.param_is_error(i)?;
71
72 return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam {
73 ty: arg,
74 kind,
75 span,
76 param_span: tcx.def_span(opaque_param.def_id),
77 }));
78 }
79 }
80
81 for (_, indices) in seen_params {
82 if indices.len() > 1 {
83 let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
84 let spans: Vec<_> = indices
85 .into_iter()
86 .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
87 .collect();
88 return Err(infcx
89 .dcx()
90 .struct_span_err(span, "non-defining opaque type use in defining scope")
91 .with_span_note(spans, format!("{descr} used multiple times"))
92 .emit());
93 }
94 }
95
96 Ok(())
97}
98
99struct LazyOpaqueTyEnv<'tcx> {
103 tcx: TyCtxt<'tcx>,
104 def_id: LocalDefId,
105
106 canonical_args: std::cell::OnceCell<ty::GenericArgsRef<'tcx>>,
112}
113
114impl<'tcx> LazyOpaqueTyEnv<'tcx> {
115 fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
116 Self { tcx, def_id, canonical_args: std::cell::OnceCell::new() }
117 }
118
119 fn param_equal_static(&self, param_index: usize) -> bool {
120 self.get_canonical_args()[param_index].expect_region().is_static()
121 }
122
123 fn params_equal(&self, param1: usize, param2: usize) -> bool {
124 let canonical_args = self.get_canonical_args();
125 canonical_args[param1] == canonical_args[param2]
126 }
127
128 fn param_is_error(&self, param_index: usize) -> Result<(), ErrorGuaranteed> {
129 self.get_canonical_args()[param_index].error_reported()
130 }
131
132 fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> {
133 if let Some(&canonical_args) = self.canonical_args.get() {
134 return canonical_args;
135 }
136
137 let &Self { tcx, def_id, .. } = self;
138 let origin = tcx.local_opaque_ty_origin(def_id);
139 let parent = match origin {
140 OpaqueTyOrigin::FnReturn { parent, .. }
141 | OpaqueTyOrigin::AsyncFn { parent, .. }
142 | OpaqueTyOrigin::TyAlias { parent, .. } => parent,
143 };
144 let param_env = tcx.param_env(parent);
145 let args = GenericArgs::identity_for_item(tcx, parent).extend_to(
146 tcx,
147 def_id.to_def_id(),
148 |param, _| {
149 tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into()
150 },
151 );
152
153 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
156 let ocx = ObligationCtxt::new(&infcx);
157
158 let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| {
159 tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds");
160 Default::default()
161 });
162 let outlives_env = OutlivesEnvironment::new(&infcx, parent, param_env, wf_tys);
163
164 let mut seen = vec![tcx.lifetimes.re_static];
165 let canonical_args = fold_regions(tcx, args, |r1, _| {
166 if r1.is_error() {
167 r1
168 } else if let Some(&r2) = seen.iter().find(|&&r2| {
169 let free_regions = outlives_env.free_region_map();
170 free_regions.sub_free_regions(tcx, r1, r2)
171 && free_regions.sub_free_regions(tcx, r2, r1)
172 }) {
173 r2
174 } else {
175 seen.push(r1);
176 r1
177 }
178 });
179 self.canonical_args.set(canonical_args).unwrap();
180 canonical_args
181 }
182}