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