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