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