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, Ty, TyCtxt,
8 TypeVisitableExt, TypingMode, fold_regions,
9};
10use rustc_span::{ErrorGuaranteed, Span};
11
12use crate::errors::NonGenericOpaqueTypeParam;
13use crate::regions::OutlivesEnvironmentBuildExt;
14use crate::traits::ObligationCtxt;
15
16#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for NonDefiningUseReason<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
NonDefiningUseReason::Tainted(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"Tainted", &__self_0),
NonDefiningUseReason::NotAParam {
opaque_type_key: __self_0,
param_index: __self_1,
span: __self_2 } =>
::core::fmt::Formatter::debug_struct_field3_finish(f,
"NotAParam", "opaque_type_key", __self_0, "param_index",
__self_1, "span", &__self_2),
NonDefiningUseReason::DuplicateParam {
opaque_type_key: __self_0,
param_indices: __self_1,
span: __self_2 } =>
::core::fmt::Formatter::debug_struct_field3_finish(f,
"DuplicateParam", "opaque_type_key", __self_0,
"param_indices", __self_1, "span", &__self_2),
}
}
}Debug)]
17pub enum NonDefiningUseReason<'tcx> {
18 Tainted(ErrorGuaranteed),
19 NotAParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_index: usize, span: Span },
20 DuplicateParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_indices: Vec<usize>, span: Span },
21}
22impl From<ErrorGuaranteed> for NonDefiningUseReason<'_> {
23 fn from(guar: ErrorGuaranteed) -> Self {
24 NonDefiningUseReason::Tainted(guar)
25 }
26}
27impl<'tcx> NonDefiningUseReason<'tcx> {
28 pub fn report(self, infcx: &InferCtxt<'tcx>) -> ErrorGuaranteed {
29 let tcx = infcx.tcx;
30 match self {
31 NonDefiningUseReason::Tainted(guar) => guar,
32 NonDefiningUseReason::NotAParam { opaque_type_key, param_index, span } => {
33 let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
34 let opaque_param = opaque_generics.param_at(param_index, tcx);
35 let kind = opaque_param.kind.descr();
36 infcx.dcx().emit_err(NonGenericOpaqueTypeParam {
37 arg: opaque_type_key.args[param_index],
38 kind,
39 span,
40 param_span: tcx.def_span(opaque_param.def_id),
41 })
42 }
43 NonDefiningUseReason::DuplicateParam { opaque_type_key, param_indices, span } => {
44 let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
45 let descr = opaque_generics.param_at(param_indices[0], tcx).kind.descr();
46 let spans: Vec<_> = param_indices
47 .into_iter()
48 .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
49 .collect();
50 infcx
51 .dcx()
52 .struct_span_err(span, "non-defining opaque type use in defining scope")
53 .with_span_note(spans, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} used multiple times", descr))
})format!("{descr} used multiple times"))
54 .emit()
55 }
56 }
57 }
58}
59
60pub fn opaque_type_has_defining_use_args<'tcx>(
67 infcx: &InferCtxt<'tcx>,
68 opaque_type_key: OpaqueTypeKey<'tcx>,
69 span: Span,
70 defining_scope_kind: DefiningScopeKind,
71) -> Result<(), NonDefiningUseReason<'tcx>> {
72 let tcx = infcx.tcx;
73 let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
74 let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
75
76 if let DefiningScopeKind::MirBorrowck = defining_scope_kind {
79 infcx
80 .tcx
81 .type_of_opaque_hir_typeck(opaque_type_key.def_id)
82 .instantiate_identity()
83 .skip_norm_wip()
84 .error_reported()?;
85 }
86
87 for (i, arg) in opaque_type_key.iter_captured_args(tcx) {
88 let arg_is_param = match arg.kind() {
89 GenericArgKind::Lifetime(lt) => match defining_scope_kind {
90 DefiningScopeKind::HirTypeck => continue,
91 DefiningScopeKind::MirBorrowck => {
92 #[allow(non_exhaustive_omitted_patterns)] match lt.kind() {
ty::ReEarlyParam(_) | ty::ReLateParam(_) => true,
_ => false,
}matches!(lt.kind(), ty::ReEarlyParam(_) | ty::ReLateParam(_))
93 || (lt.is_static() && opaque_env.param_equal_static(i))
94 }
95 },
96 GenericArgKind::Type(ty) => #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
ty::Param(_) => true,
_ => false,
}matches!(ty.kind(), ty::Param(_)),
97 GenericArgKind::Const(ct) => #[allow(non_exhaustive_omitted_patterns)] match ct.kind() {
ty::ConstKind::Param(_) => true,
_ => false,
}matches!(ct.kind(), ty::ConstKind::Param(_)),
98 };
99
100 if arg_is_param {
101 let seen_where = seen_params.entry(arg).or_default();
105 if !seen_where.first().is_some_and(|&prev_i| opaque_env.params_equal(i, prev_i)) {
106 seen_where.push(i);
107 }
108 } else {
109 opaque_env.param_is_error(i)?;
111 return Err(NonDefiningUseReason::NotAParam { opaque_type_key, param_index: i, span });
112 }
113 }
114
115 for (_, param_indices) in seen_params {
116 if param_indices.len() > 1 {
117 return Err(NonDefiningUseReason::DuplicateParam {
118 opaque_type_key,
119 param_indices,
120 span,
121 });
122 }
123 }
124
125 Ok(())
126}
127
128struct LazyOpaqueTyEnv<'tcx> {
132 tcx: TyCtxt<'tcx>,
133 def_id: LocalDefId,
134
135 canonical_args: std::cell::OnceCell<ty::GenericArgsRef<'tcx>>,
141}
142
143impl<'tcx> LazyOpaqueTyEnv<'tcx> {
144 fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
145 Self { tcx, def_id, canonical_args: std::cell::OnceCell::new() }
146 }
147
148 fn param_equal_static(&self, param_index: usize) -> bool {
149 self.get_canonical_args()[param_index].expect_region().is_static()
150 }
151
152 fn params_equal(&self, param1: usize, param2: usize) -> bool {
153 let canonical_args = self.get_canonical_args();
154 canonical_args[param1] == canonical_args[param2]
155 }
156
157 fn param_is_error(&self, param_index: usize) -> Result<(), ErrorGuaranteed> {
158 self.get_canonical_args()[param_index].error_reported()
159 }
160
161 fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> {
162 if let Some(&canonical_args) = self.canonical_args.get() {
163 return canonical_args;
164 }
165
166 let &Self { tcx, def_id, .. } = self;
167 let origin = tcx.local_opaque_ty_origin(def_id);
168 let parent = match origin {
169 OpaqueTyOrigin::FnReturn { parent, .. }
170 | OpaqueTyOrigin::AsyncFn { parent, .. }
171 | OpaqueTyOrigin::TyAlias { parent, .. } => parent,
172 };
173 let param_env = tcx.param_env(parent);
174 let args = GenericArgs::identity_for_item(tcx, parent).extend_to(
175 tcx,
176 def_id.to_def_id(),
177 |param, _| {
178 tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into()
179 },
180 );
181
182 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
185 let ocx = ObligationCtxt::new(&infcx);
186
187 let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| {
188 tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds");
189 Default::default()
190 });
191 let outlives_env = OutlivesEnvironment::new(&infcx, parent, param_env, wf_tys);
192
193 let mut seen = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[tcx.lifetimes.re_static]))vec![tcx.lifetimes.re_static];
194 let canonical_args = fold_regions(tcx, args, |r1, _| {
195 if r1.is_error() {
196 r1
197 } else if let Some(&r2) = seen.iter().find(|&&r2| {
198 let free_regions = outlives_env.free_region_map();
199 free_regions.sub_free_regions(tcx, r1, r2)
200 && free_regions.sub_free_regions(tcx, r2, r1)
201 }) {
202 r2
203 } else {
204 seen.push(r1);
205 r1
206 }
207 });
208 self.canonical_args.set(canonical_args).unwrap();
209 canonical_args
210 }
211}
212
213pub fn report_item_does_not_constrain_error<'tcx>(
214 tcx: TyCtxt<'tcx>,
215 item_def_id: LocalDefId,
216 def_id: LocalDefId,
217 non_defining_use: Option<(OpaqueTypeKey<'tcx>, Span)>,
218) -> ErrorGuaranteed {
219 let span = tcx.def_ident_span(item_def_id).unwrap_or_else(|| tcx.def_span(item_def_id));
220 let opaque_type_span = tcx.def_span(def_id);
221 let opaque_type_name = tcx.def_path_str(def_id);
222
223 let mut err =
224 tcx.dcx().struct_span_err(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("item does not constrain `{0}`",
opaque_type_name))
})format!("item does not constrain `{opaque_type_name}`"));
225 err.note("consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`");
226 err.span_note(opaque_type_span, "this opaque type is supposed to be constrained");
227 if let Some((key, span)) = non_defining_use {
228 let opaque_ty = Ty::new_opaque(tcx, key.def_id.into(), key.args);
229 err.span_note(
230 span,
231 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("this use of `{0}` does not have unique universal generic arguments",
opaque_ty))
})format!("this use of `{opaque_ty}` does not have unique universal generic arguments"),
232 );
233 }
234 err.emit()
235}