1use rustc_data_structures::fx::FxIndexSet;
5use rustc_errors::ErrorGuaranteed;
6use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
7use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION;
8use rustc_middle::ty::{
9 self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
10};
11use rustc_middle::{bug, span_bug};
12use rustc_span::def_id::{DefId, LocalDefId};
13use rustc_trait_selection::traits::{
14 self, IsFirstInputType, OrphanCheckErr, OrphanCheckMode, UncoveredTyParams,
15};
16use tracing::{debug, instrument};
17
18use crate::errors;
19
20#[instrument(level = "debug", skip(tcx))]
21pub(crate) fn orphan_check_impl(
22 tcx: TyCtxt<'_>,
23 impl_def_id: LocalDefId,
24) -> Result<(), ErrorGuaranteed> {
25 let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
26 trait_ref.error_reported()?;
27
28 match orphan_check(tcx, impl_def_id, OrphanCheckMode::Proper) {
29 Ok(()) => {}
30 Err(err) => match orphan_check(tcx, impl_def_id, OrphanCheckMode::Compat) {
31 Ok(()) => match err {
32 OrphanCheckErr::UncoveredTyParams(uncovered_ty_params) => {
33 lint_uncovered_ty_params(tcx, uncovered_ty_params, impl_def_id)
34 }
35 OrphanCheckErr::NonLocalInputType(_) => {
36 bug!("orphanck: shouldn't've gotten non-local input tys in compat mode")
37 }
38 },
39 Err(err) => return Err(emit_orphan_check_error(tcx, trait_ref, impl_def_id, err)),
40 },
41 }
42
43 let trait_def_id = trait_ref.def_id;
44
45 debug!(
78 "trait_ref={:?} trait_def_id={:?} trait_is_auto={}",
79 trait_ref,
80 trait_def_id,
81 tcx.trait_is_auto(trait_def_id)
82 );
83
84 if tcx.trait_is_auto(trait_def_id) {
85 let self_ty = trait_ref.self_ty();
86
87 enum LocalImpl {
123 Allow,
124 Disallow { problematic_kind: &'static str },
125 }
126
127 enum NonlocalImpl {
135 Allow,
136 DisallowBecauseNonlocal,
137 DisallowOther,
138 }
139
140 let (local_impl, nonlocal_impl) = match self_ty.kind() {
143 ty::Adt(self_def, _) => (
146 LocalImpl::Allow,
147 if self_def.did().is_local() {
148 NonlocalImpl::Allow
149 } else {
150 NonlocalImpl::DisallowBecauseNonlocal
151 },
152 ),
153
154 ty::Foreign(did) => (
157 LocalImpl::Allow,
158 if did.is_local() {
159 NonlocalImpl::Allow
160 } else {
161 NonlocalImpl::DisallowBecauseNonlocal
162 },
163 ),
164
165 ty::Dynamic(..) => (
167 LocalImpl::Disallow { problematic_kind: "trait object" },
168 NonlocalImpl::DisallowOther,
169 ),
170
171 ty::Param(..) => (
174 if self_ty.is_sized(tcx, ty::TypingEnv::non_body_analysis(tcx, impl_def_id)) {
175 LocalImpl::Allow
176 } else {
177 LocalImpl::Disallow { problematic_kind: "generic type" }
178 },
179 NonlocalImpl::DisallowOther,
180 ),
181
182 ty::Alias(kind, _) => {
183 let problematic_kind = match kind {
184 ty::Projection => "associated type",
190 ty::Weak => "type alias",
193 ty::Opaque => "opaque type",
196 ty::Inherent => "associated type",
205 };
206 (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
207 }
208
209 ty::Pat(..) => (
210 LocalImpl::Disallow { problematic_kind: "pattern type" },
211 NonlocalImpl::DisallowOther,
212 ),
213
214 ty::Bool
215 | ty::Char
216 | ty::Int(..)
217 | ty::Uint(..)
218 | ty::Float(..)
219 | ty::Str
220 | ty::Array(..)
221 | ty::Slice(..)
222 | ty::RawPtr(..)
223 | ty::Ref(..)
224 | ty::FnDef(..)
225 | ty::FnPtr(..)
226 | ty::Never
227 | ty::Tuple(..)
228 | ty::UnsafeBinder(_) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
229
230 ty::Closure(..)
231 | ty::CoroutineClosure(..)
232 | ty::Coroutine(..)
233 | ty::CoroutineWitness(..)
234 | ty::Bound(..)
235 | ty::Placeholder(..)
236 | ty::Infer(..) => {
237 let sp = tcx.def_span(impl_def_id);
238 span_bug!(sp, "weird self type for autotrait impl")
239 }
240
241 ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow),
242 };
243
244 if trait_def_id.is_local() {
245 match local_impl {
246 LocalImpl::Allow => {}
247 LocalImpl::Disallow { problematic_kind } => {
248 return Err(tcx.dcx().emit_err(errors::TraitsWithDefaultImpl {
249 span: tcx.def_span(impl_def_id),
250 traits: tcx.def_path_str(trait_def_id),
251 problematic_kind,
252 self_ty,
253 }));
254 }
255 }
256 } else {
257 match nonlocal_impl {
258 NonlocalImpl::Allow => {}
259 NonlocalImpl::DisallowBecauseNonlocal => {
260 return Err(tcx.dcx().emit_err(errors::CrossCrateTraitsDefined {
261 span: tcx.def_span(impl_def_id),
262 traits: tcx.def_path_str(trait_def_id),
263 }));
264 }
265 NonlocalImpl::DisallowOther => {
266 return Err(tcx.dcx().emit_err(errors::CrossCrateTraits {
267 span: tcx.def_span(impl_def_id),
268 traits: tcx.def_path_str(trait_def_id),
269 self_ty,
270 }));
271 }
272 }
273 }
274 }
275
276 Ok(())
277}
278
279#[instrument(level = "debug", skip(tcx), ret)]
288fn orphan_check<'tcx>(
289 tcx: TyCtxt<'tcx>,
290 impl_def_id: LocalDefId,
291 mode: OrphanCheckMode,
292) -> Result<(), OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>> {
293 let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
296 debug!(trait_ref = ?trait_ref.skip_binder());
297
298 if let Some(def_id) = trait_ref.skip_binder().def_id.as_local() {
300 debug!("trait {def_id:?} is local to current crate");
301 return Ok(());
302 }
303
304 let infcx = tcx.infer_ctxt().build(TypingMode::Coherence);
306 let cause = traits::ObligationCause::dummy();
307 let args = infcx.fresh_args_for_item(cause.span, impl_def_id.to_def_id());
308 let trait_ref = trait_ref.instantiate(tcx, args);
309
310 let lazily_normalize_ty = |user_ty: Ty<'tcx>| {
311 let ty::Alias(..) = user_ty.kind() else { return Ok(user_ty) };
312
313 let ocx = traits::ObligationCtxt::new(&infcx);
314 let ty = ocx.normalize(&cause, ty::ParamEnv::empty(), user_ty);
315 let ty = infcx.resolve_vars_if_possible(ty);
316 let errors = ocx.select_where_possible();
317 if !errors.is_empty() {
318 return Ok(user_ty);
319 }
320
321 let ty = if infcx.next_trait_solver() {
322 ocx.structurally_normalize_ty(
323 &cause,
324 ty::ParamEnv::empty(),
325 infcx.resolve_vars_if_possible(ty),
326 )
327 .unwrap_or(ty)
328 } else {
329 ty
330 };
331
332 Ok::<_, !>(ty)
333 };
334
335 let result = traits::orphan_check_trait_ref(
336 &infcx,
337 trait_ref,
338 traits::InCrate::Local { mode },
339 lazily_normalize_ty,
340 )
341 .into_ok();
342
343 result.map_err(|err| match err {
345 OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
346 let mut collector =
347 UncoveredTyParamCollector { infcx: &infcx, uncovered_params: Default::default() };
348 uncovered.visit_with(&mut collector);
349 debug_assert!(!collector.uncovered_params.is_empty());
351
352 OrphanCheckErr::UncoveredTyParams(UncoveredTyParams {
353 uncovered: collector.uncovered_params,
354 local_ty,
355 })
356 }
357 OrphanCheckErr::NonLocalInputType(tys) => {
358 let tys = infcx.probe(|_| {
359 for (arg, id_arg) in
362 std::iter::zip(args, ty::GenericArgs::identity_for_item(tcx, impl_def_id))
363 {
364 let _ = infcx.at(&cause, ty::ParamEnv::empty()).eq(
365 DefineOpaqueTypes::No,
366 arg,
367 id_arg,
368 );
369 }
370 infcx.resolve_vars_if_possible(tys)
371 });
372 OrphanCheckErr::NonLocalInputType(tys)
373 }
374 })
375}
376
377fn emit_orphan_check_error<'tcx>(
378 tcx: TyCtxt<'tcx>,
379 trait_ref: ty::TraitRef<'tcx>,
380 impl_def_id: LocalDefId,
381 err: traits::OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>,
382) -> ErrorGuaranteed {
383 match err {
384 traits::OrphanCheckErr::NonLocalInputType(tys) => {
385 let item = tcx.hir_expect_item(impl_def_id);
386 let impl_ = item.expect_impl();
387 let hir_trait_ref = impl_.of_trait.as_ref().unwrap();
388
389 let span = tcx.def_span(impl_def_id);
390 let mut diag = tcx.dcx().create_err(match trait_ref.self_ty().kind() {
391 ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span, note: () },
392 _ if trait_ref.self_ty().is_primitive() => {
393 errors::OnlyCurrentTraits::Primitive { span, note: () }
394 }
395 _ => errors::OnlyCurrentTraits::Arbitrary { span, note: () },
396 });
397
398 for &(mut ty, is_target_ty) in &tys {
399 let span = if matches!(is_target_ty, IsFirstInputType::Yes) {
400 impl_.self_ty.span
402 } else {
403 hir_trait_ref.path.span
405 };
406
407 ty = tcx.erase_regions(ty);
408
409 let is_foreign =
410 !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
411
412 match *ty.kind() {
413 ty::Slice(_) => {
414 if is_foreign {
415 diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
416 } else {
417 diag.subdiagnostic(errors::OnlyCurrentTraitsName {
418 span,
419 name: "slices",
420 });
421 }
422 }
423 ty::Array(..) => {
424 if is_foreign {
425 diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
426 } else {
427 diag.subdiagnostic(errors::OnlyCurrentTraitsName {
428 span,
429 name: "arrays",
430 });
431 }
432 }
433 ty::Tuple(..) => {
434 if is_foreign {
435 diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
436 } else {
437 diag.subdiagnostic(errors::OnlyCurrentTraitsName {
438 span,
439 name: "tuples",
440 });
441 }
442 }
443 ty::Alias(ty::Opaque, ..) => {
444 diag.subdiagnostic(errors::OnlyCurrentTraitsOpaque { span });
445 }
446 ty::RawPtr(ptr_ty, mutbl) => {
447 if !trait_ref.self_ty().has_param() {
448 diag.subdiagnostic(errors::OnlyCurrentTraitsPointerSugg {
449 wrapper_span: impl_.self_ty.span,
450 struct_span: item.span.shrink_to_lo(),
451 mut_key: mutbl.prefix_str(),
452 ptr_ty,
453 });
454 }
455 diag.subdiagnostic(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
456 }
457 ty::Adt(adt_def, _) => {
458 diag.subdiagnostic(errors::OnlyCurrentTraitsAdt {
459 span,
460 name: tcx.def_path_str(adt_def.did()),
461 });
462 }
463 _ => {
464 diag.subdiagnostic(errors::OnlyCurrentTraitsTy { span, ty });
465 }
466 }
467 }
468
469 diag.emit()
470 }
471 traits::OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
472 let mut reported = None;
473 for param_def_id in uncovered {
474 let name = tcx.item_ident(param_def_id);
475 let span = name.span;
476
477 reported.get_or_insert(match local_ty {
478 Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
479 span,
480 note: (),
481 param: name,
482 local_type,
483 }),
484 None => tcx.dcx().emit_err(errors::TyParamSome { span, note: (), param: name }),
485 });
486 }
487 reported.unwrap() }
489 }
490}
491
492fn lint_uncovered_ty_params<'tcx>(
493 tcx: TyCtxt<'tcx>,
494 UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<TyCtxt<'tcx>, FxIndexSet<DefId>>,
495 impl_def_id: LocalDefId,
496) {
497 let hir_id = tcx.local_def_id_to_hir_id(impl_def_id);
498
499 for param_def_id in uncovered {
500 let span = tcx.def_ident_span(param_def_id).unwrap();
501 let name = tcx.item_ident(param_def_id);
502
503 match local_ty {
504 Some(local_type) => tcx.emit_node_span_lint(
505 UNCOVERED_PARAM_IN_PROJECTION,
506 hir_id,
507 span,
508 errors::TyParamFirstLocalLint { span, note: (), param: name, local_type },
509 ),
510 None => tcx.emit_node_span_lint(
511 UNCOVERED_PARAM_IN_PROJECTION,
512 hir_id,
513 span,
514 errors::TyParamSomeLint { span, note: (), param: name },
515 ),
516 };
517 }
518}
519
520struct UncoveredTyParamCollector<'cx, 'tcx> {
521 infcx: &'cx InferCtxt<'tcx>,
522 uncovered_params: FxIndexSet<DefId>,
523}
524
525impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'_, 'tcx> {
526 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
527 if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
528 return;
529 }
530 let ty::Infer(ty::TyVar(vid)) = *ty.kind() else {
531 return ty.super_visit_with(self);
532 };
533 let origin = self.infcx.type_var_origin(vid);
534 if let Some(def_id) = origin.param_def_id {
535 self.uncovered_params.insert(def_id);
536 }
537 }
538
539 fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
540 if ct.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
541 ct.super_visit_with(self)
542 }
543 }
544}