rustc_hir_analysis/coherence/
orphan.rs1use 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).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::Free => "type alias",
193 ty::Opaque => "opaque type",
196 ty::Inherent => "associated type",
205 };
206 (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
207 }
208
209 ty::Bool
210 | ty::Pat(..)
211 | ty::Char
212 | ty::Int(..)
213 | ty::Uint(..)
214 | ty::Float(..)
215 | ty::Str
216 | ty::Array(..)
217 | ty::Slice(..)
218 | ty::RawPtr(..)
219 | ty::Ref(..)
220 | ty::FnDef(..)
221 | ty::FnPtr(..)
222 | ty::Never
223 | ty::Tuple(..)
224 | ty::UnsafeBinder(_) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
225
226 ty::Closure(..)
227 | ty::CoroutineClosure(..)
228 | ty::Coroutine(..)
229 | ty::CoroutineWitness(..) => {
230 return Err(tcx
231 .dcx()
232 .delayed_bug("cannot define inherent `impl` for closure types"));
233 }
234 ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => {
235 let sp = tcx.def_span(impl_def_id);
236 span_bug!(sp, "weird self type for autotrait impl")
237 }
238
239 ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow),
240 };
241
242 if trait_def_id.is_local() {
243 match local_impl {
244 LocalImpl::Allow => {}
245 LocalImpl::Disallow { problematic_kind } => {
246 return Err(tcx.dcx().emit_err(errors::TraitsWithDefaultImpl {
247 span: tcx.def_span(impl_def_id),
248 traits: tcx.def_path_str(trait_def_id),
249 problematic_kind,
250 self_ty,
251 }));
252 }
253 }
254 } else {
255 match nonlocal_impl {
256 NonlocalImpl::Allow => {}
257 NonlocalImpl::DisallowBecauseNonlocal => {
258 return Err(tcx.dcx().emit_err(errors::CrossCrateTraitsDefined {
259 span: tcx.def_span(impl_def_id),
260 traits: tcx.def_path_str(trait_def_id),
261 }));
262 }
263 NonlocalImpl::DisallowOther => {
264 return Err(tcx.dcx().emit_err(errors::CrossCrateTraits {
265 span: tcx.def_span(impl_def_id),
266 traits: tcx.def_path_str(trait_def_id),
267 self_ty,
268 }));
269 }
270 }
271 }
272 }
273
274 Ok(())
275}
276
277#[instrument(level = "debug", skip(tcx), ret)]
286fn orphan_check<'tcx>(
287 tcx: TyCtxt<'tcx>,
288 impl_def_id: LocalDefId,
289 mode: OrphanCheckMode,
290) -> Result<(), OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>> {
291 let trait_ref = tcx.impl_trait_ref(impl_def_id);
294 debug!(trait_ref = ?trait_ref.skip_binder());
295
296 if let Some(def_id) = trait_ref.skip_binder().def_id.as_local() {
298 debug!("trait {def_id:?} is local to current crate");
299 return Ok(());
300 }
301
302 let infcx = tcx.infer_ctxt().build(TypingMode::Coherence);
304 let cause = traits::ObligationCause::dummy();
305 let args = infcx.fresh_args_for_item(cause.span, impl_def_id.to_def_id());
306 let trait_ref = trait_ref.instantiate(tcx, args);
307
308 let lazily_normalize_ty = |user_ty: Ty<'tcx>| {
309 let ty::Alias(..) = user_ty.kind() else { return Ok(user_ty) };
310
311 let ocx = traits::ObligationCtxt::new(&infcx);
312 let ty = ocx.normalize(&cause, ty::ParamEnv::empty(), user_ty);
313 let ty = infcx.resolve_vars_if_possible(ty);
314 let errors = ocx.try_evaluate_obligations();
315 if !errors.is_empty() {
316 return Ok(user_ty);
317 }
318
319 let ty = if infcx.next_trait_solver() {
320 ocx.structurally_normalize_ty(
321 &cause,
322 ty::ParamEnv::empty(),
323 infcx.resolve_vars_if_possible(ty),
324 )
325 .unwrap_or(ty)
326 } else {
327 ty
328 };
329
330 Ok::<_, !>(ty)
331 };
332
333 let result = traits::orphan_check_trait_ref(
334 &infcx,
335 trait_ref,
336 traits::InCrate::Local { mode },
337 lazily_normalize_ty,
338 )
339 .into_ok();
340
341 result.map_err(|err| match err {
343 OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
344 let mut collector =
345 UncoveredTyParamCollector { infcx: &infcx, uncovered_params: Default::default() };
346 uncovered.visit_with(&mut collector);
347 debug_assert!(!collector.uncovered_params.is_empty());
349
350 OrphanCheckErr::UncoveredTyParams(UncoveredTyParams {
351 uncovered: collector.uncovered_params,
352 local_ty,
353 })
354 }
355 OrphanCheckErr::NonLocalInputType(tys) => {
356 let tys = infcx.probe(|_| {
357 for (arg, id_arg) in
360 std::iter::zip(args, ty::GenericArgs::identity_for_item(tcx, impl_def_id))
361 {
362 let _ = infcx.at(&cause, ty::ParamEnv::empty()).eq(
363 DefineOpaqueTypes::No,
364 arg,
365 id_arg,
366 );
367 }
368 infcx.resolve_vars_if_possible(tys)
369 });
370 OrphanCheckErr::NonLocalInputType(tys)
371 }
372 })
373}
374
375fn emit_orphan_check_error<'tcx>(
376 tcx: TyCtxt<'tcx>,
377 trait_ref: ty::TraitRef<'tcx>,
378 impl_def_id: LocalDefId,
379 err: traits::OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>,
380) -> ErrorGuaranteed {
381 match err {
382 traits::OrphanCheckErr::NonLocalInputType(tys) => {
383 let item = tcx.hir_expect_item(impl_def_id);
384 let impl_ = item.expect_impl();
385 let of_trait = impl_.of_trait.unwrap();
386
387 let span = tcx.def_span(impl_def_id);
388 let mut diag = tcx.dcx().create_err(match trait_ref.self_ty().kind() {
389 ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span, note: () },
390 _ if trait_ref.self_ty().is_primitive() => {
391 errors::OnlyCurrentTraits::Primitive { span, note: () }
392 }
393 _ => errors::OnlyCurrentTraits::Arbitrary { span, note: () },
394 });
395
396 for &(mut ty, is_target_ty) in &tys {
397 let span = if matches!(is_target_ty, IsFirstInputType::Yes) {
398 impl_.self_ty.span
400 } else {
401 of_trait.trait_ref.path.span
403 };
404
405 ty = tcx.erase_and_anonymize_regions(ty);
406
407 let is_foreign =
408 !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
409
410 match *ty.kind() {
411 ty::Slice(_) => {
412 if is_foreign {
413 diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
414 } else {
415 diag.subdiagnostic(errors::OnlyCurrentTraitsName {
416 span,
417 name: "slices",
418 });
419 }
420 }
421 ty::Array(..) => {
422 if is_foreign {
423 diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
424 } else {
425 diag.subdiagnostic(errors::OnlyCurrentTraitsName {
426 span,
427 name: "arrays",
428 });
429 }
430 }
431 ty::Tuple(..) => {
432 if is_foreign {
433 diag.subdiagnostic(errors::OnlyCurrentTraitsForeign { span });
434 } else {
435 diag.subdiagnostic(errors::OnlyCurrentTraitsName {
436 span,
437 name: "tuples",
438 });
439 }
440 }
441 ty::Alias(ty::Opaque, ..) => {
442 diag.subdiagnostic(errors::OnlyCurrentTraitsOpaque { span });
443 }
444 ty::RawPtr(ptr_ty, mutbl) => {
445 if !trait_ref.self_ty().has_param() {
446 diag.subdiagnostic(errors::OnlyCurrentTraitsPointerSugg {
447 wrapper_span: impl_.self_ty.span,
448 struct_span: item.span.shrink_to_lo(),
449 mut_key: mutbl.prefix_str(),
450 ptr_ty,
451 });
452 }
453 diag.subdiagnostic(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
454 }
455 ty::Adt(adt_def, _) => {
456 diag.subdiagnostic(errors::OnlyCurrentTraitsAdt {
457 span,
458 name: tcx.def_path_str(adt_def.did()),
459 });
460 }
461 _ => {
462 diag.subdiagnostic(errors::OnlyCurrentTraitsTy { span, ty });
463 }
464 }
465 }
466
467 diag.emit()
468 }
469 traits::OrphanCheckErr::UncoveredTyParams(UncoveredTyParams { uncovered, local_ty }) => {
470 let mut reported = None;
471 for param_def_id in uncovered {
472 let name = tcx.item_ident(param_def_id);
473 let span = name.span;
474
475 reported.get_or_insert(match local_ty {
476 Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
477 span,
478 note: (),
479 param: name,
480 local_type,
481 }),
482 None => tcx.dcx().emit_err(errors::TyParamSome { span, note: (), param: name }),
483 });
484 }
485 reported.unwrap() }
487 }
488}
489
490fn lint_uncovered_ty_params<'tcx>(
491 tcx: TyCtxt<'tcx>,
492 UncoveredTyParams { uncovered, local_ty }: UncoveredTyParams<TyCtxt<'tcx>, FxIndexSet<DefId>>,
493 impl_def_id: LocalDefId,
494) {
495 let hir_id = tcx.local_def_id_to_hir_id(impl_def_id);
496
497 for param_def_id in uncovered {
498 let span = tcx.def_ident_span(param_def_id).unwrap();
499 let name = tcx.item_ident(param_def_id);
500
501 match local_ty {
502 Some(local_type) => tcx.emit_node_span_lint(
503 UNCOVERED_PARAM_IN_PROJECTION,
504 hir_id,
505 span,
506 errors::TyParamFirstLocalLint { span, note: (), param: name, local_type },
507 ),
508 None => tcx.emit_node_span_lint(
509 UNCOVERED_PARAM_IN_PROJECTION,
510 hir_id,
511 span,
512 errors::TyParamSomeLint { span, note: (), param: name },
513 ),
514 };
515 }
516}
517
518struct UncoveredTyParamCollector<'cx, 'tcx> {
519 infcx: &'cx InferCtxt<'tcx>,
520 uncovered_params: FxIndexSet<DefId>,
521}
522
523impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'_, 'tcx> {
524 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
525 if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
526 return;
527 }
528 let ty::Infer(ty::TyVar(vid)) = *ty.kind() else {
529 return ty.super_visit_with(self);
530 };
531 let origin = self.infcx.type_var_origin(vid);
532 if let Some(def_id) = origin.param_def_id {
533 self.uncovered_params.insert(def_id);
534 }
535 }
536
537 fn visit_const(&mut self, ct: ty::Const<'tcx>) -> Self::Result {
538 if ct.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
539 ct.super_visit_with(self)
540 }
541 }
542}