@@ -6,14 +6,13 @@ use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed};
66use rustc_infer:: infer:: { DefineOpaqueTypes , InferCtxt , TyCtxtInferExt } ;
77use rustc_lint_defs:: builtin:: UNCOVERED_PARAM_IN_PROJECTION ;
88use rustc_middle:: ty:: {
9- self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor , TypingMode ,
9+ self , Ty , TyCtxt , TypeFlags , TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor ,
10+ TypingMode ,
1011} ;
1112use rustc_middle:: { bug, span_bug} ;
12- use rustc_span:: def_id:: { DefId , LocalDefId } ;
13+ use rustc_span:: def_id:: LocalDefId ;
1314use rustc_span:: { Ident , Span } ;
14- use rustc_trait_selection:: traits:: {
15- self , InSelfTy , OrphanCheckErr , OrphanCheckMode , UncoveredTyParams ,
16- } ;
15+ use rustc_trait_selection:: traits:: { self , InSelfTy , OrphanCheckErr , OrphanCheckMode , UncoveredTy } ;
1716use tracing:: { debug, instrument} ;
1817
1918use crate :: errors;
@@ -30,25 +29,34 @@ pub(crate) fn orphan_check_impl(
3029 Ok ( ( ) ) => { }
3130 Err ( err) => match orphan_check ( tcx, impl_def_id, OrphanCheckMode :: Compat ) {
3231 Ok ( ( ) ) => match err {
33- OrphanCheckErr :: UncoveredTyParams ( uncovered_ty_params) => {
34- let hir_id = tcx. local_def_id_to_hir_id ( impl_def_id) ;
35-
36- for param_def_id in uncovered_ty_params. uncovered {
37- let ident = tcx. item_ident ( param_def_id) ;
38-
39- tcx. node_span_lint (
40- UNCOVERED_PARAM_IN_PROJECTION ,
41- hir_id,
42- ident. span ,
43- |diag| {
44- decorate_uncovered_ty_params_diag (
45- diag,
46- ident. span ,
47- ident,
48- uncovered_ty_params. local_ty ,
49- )
50- } ,
51- ) ;
32+ OrphanCheckErr :: UncoveredTy ( UncoveredTy { uncovered, local_ty, in_self_ty } ) => {
33+ let item = tcx. hir_expect_item ( impl_def_id) ;
34+ let impl_ = item. expect_impl ( ) ;
35+ let hir_trait_ref = impl_. of_trait . as_ref ( ) . unwrap ( ) ;
36+
37+ // FIXME: Dedupe!
38+ // Given `impl<A, B> C<B> for D<A>`,
39+ let span = match in_self_ty {
40+ InSelfTy :: Yes => impl_. self_ty . span , // point at `D<A>`.
41+ InSelfTy :: No => hir_trait_ref. path . span , // point at `C<B>`.
42+ } ;
43+
44+ for ty in uncovered {
45+ match ty {
46+ UncoveredTyKind :: TyParam ( ident) => tcx. node_span_lint (
47+ UNCOVERED_PARAM_IN_PROJECTION ,
48+ item. hir_id ( ) ,
49+ ident. span ,
50+ |diag| decorate_uncovered_ty_diag ( diag, ident. span , ty, local_ty) ,
51+ ) ,
52+ // FIXME(fmease): This one is hard to explain ^^'
53+ UncoveredTyKind :: Unknown => {
54+ let mut diag = tcx. dcx ( ) . struct_span_err ( span, "" ) ;
55+ decorate_uncovered_ty_diag ( & mut diag, span, ty, local_ty) ;
56+ diag. emit ( ) ;
57+ }
58+ _ => bug ! ( ) ,
59+ }
5260 }
5361 }
5462 OrphanCheckErr :: NonLocalInputType ( _) => {
@@ -295,20 +303,13 @@ pub(crate) fn orphan_check_impl(
295303 Ok ( ( ) )
296304}
297305
298- /// Checks the coherence orphan rules.
299- ///
300- /// `impl_def_id` should be the `DefId` of a trait impl.
301- ///
302- /// To pass, either the trait must be local, or else two conditions must be satisfied:
303- ///
304- /// 1. All type parameters in `Self` must be "covered" by some local type constructor.
305- /// 2. Some local type must appear in `Self`.
306+ /// Checks the coherence orphan rules for trait impl given by `impl_def_id`.
306307#[ instrument( level = "debug" , skip( tcx) , ret) ]
307308fn orphan_check < ' tcx > (
308309 tcx : TyCtxt < ' tcx > ,
309310 impl_def_id : LocalDefId ,
310311 mode : OrphanCheckMode ,
311- ) -> Result < ( ) , OrphanCheckErr < TyCtxt < ' tcx > , FxIndexSet < DefId > > > {
312+ ) -> Result < ( ) , OrphanCheckErr < TyCtxt < ' tcx > , UncoveredTys < ' tcx > > > {
312313 // We only accept this routine to be invoked on implementations
313314 // of a trait, not inherent implementations.
314315 let trait_ref = tcx. impl_trait_ref ( impl_def_id) . unwrap ( ) ;
@@ -361,15 +362,17 @@ fn orphan_check<'tcx>(
361362
362363 // (2) Try to map the remaining inference vars back to generic params.
363364 result. map_err ( |err| match err {
364- OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams { uncovered, local_ty } ) => {
365+ OrphanCheckErr :: UncoveredTy ( UncoveredTy { uncovered, in_self_ty , local_ty } ) => {
365366 let mut collector =
366- UncoveredTyParamCollector { infcx : & infcx, uncovered_params : Default :: default ( ) } ;
367+ UncoveredTyCollector { infcx : & infcx, uncovered : Default :: default ( ) } ;
367368 uncovered. visit_with ( & mut collector) ;
368- // FIXME(fmease): This is very likely reachable.
369- debug_assert ! ( !collector. uncovered_params. is_empty( ) ) ;
369+ if collector. uncovered . is_empty ( ) {
370+ collector. uncovered . insert ( UncoveredTyKind :: Unknown ) ;
371+ }
370372
371- OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams {
372- uncovered : collector. uncovered_params ,
373+ OrphanCheckErr :: UncoveredTy ( UncoveredTy {
374+ uncovered : collector. uncovered ,
375+ in_self_ty,
373376 local_ty,
374377 } )
375378 }
@@ -397,14 +400,20 @@ fn emit_orphan_check_error<'tcx>(
397400 tcx : TyCtxt < ' tcx > ,
398401 trait_ref : ty:: TraitRef < ' tcx > ,
399402 impl_def_id : LocalDefId ,
400- err : traits :: OrphanCheckErr < TyCtxt < ' tcx > , FxIndexSet < DefId > > ,
403+ err : OrphanCheckErr < TyCtxt < ' tcx > , UncoveredTys < ' tcx > > ,
401404) -> ErrorGuaranteed {
402- match err {
403- traits:: OrphanCheckErr :: NonLocalInputType ( tys) => {
404- let item = tcx. hir_expect_item ( impl_def_id) ;
405- let impl_ = item. expect_impl ( ) ;
406- let hir_trait_ref = impl_. of_trait . as_ref ( ) . unwrap ( ) ;
405+ let item = tcx. hir_expect_item ( impl_def_id) ;
406+ let impl_ = item. expect_impl ( ) ;
407+ let hir_trait_ref = impl_. of_trait . as_ref ( ) . unwrap ( ) ;
408+
409+ // Given `impl<A, B> C<B> for D<A>`,
410+ let impl_trait_ref_span = |in_self_ty| match in_self_ty {
411+ InSelfTy :: Yes => impl_. self_ty . span , // point at `D<A>`.
412+ InSelfTy :: No => hir_trait_ref. path . span , // point at `C<B>`.
413+ } ;
407414
415+ match err {
416+ OrphanCheckErr :: NonLocalInputType ( tys) => {
408417 let span = tcx. def_span ( impl_def_id) ;
409418 let mut diag = tcx. dcx ( ) . create_err ( match trait_ref. self_ty ( ) . kind ( ) {
410419 ty:: Adt ( ..) => errors:: OnlyCurrentTraits :: Outside { span, note : ( ) } ,
@@ -415,16 +424,11 @@ fn emit_orphan_check_error<'tcx>(
415424 } ) ;
416425
417426 for & ( mut ty, in_self_ty) in & tys {
418- // Given `impl<A, B> C<B> for D<A>`,
419- let span = match in_self_ty {
420- InSelfTy :: Yes => impl_. self_ty . span , // point at `D<A>`.
421- InSelfTy :: No => hir_trait_ref. path . span , // point at `C<B>`.
422- } ;
427+ let span = impl_trait_ref_span ( in_self_ty) ;
428+ let is_foreign = !trait_ref. def_id . is_local ( ) && matches ! ( in_self_ty, InSelfTy :: No ) ;
423429
424430 ty = tcx. erase_regions ( ty) ;
425431
426- let is_foreign = !trait_ref. def_id . is_local ( ) && matches ! ( in_self_ty, InSelfTy :: No ) ;
427-
428432 match * ty. kind ( ) {
429433 ty:: Slice ( _) => {
430434 if is_foreign {
@@ -484,73 +488,121 @@ fn emit_orphan_check_error<'tcx>(
484488
485489 diag. emit ( )
486490 }
487- traits:: OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams { uncovered, local_ty } ) => {
491+ OrphanCheckErr :: UncoveredTy ( UncoveredTy { uncovered, in_self_ty, local_ty } ) => {
492+ let span = impl_trait_ref_span ( in_self_ty) ;
493+
488494 let mut guar = None ;
489- for param_def_id in uncovered {
490- let ident = tcx. item_ident ( param_def_id) ;
491- let mut diag = tcx. dcx ( ) . struct_span_err ( ident. span , "" ) ;
492- decorate_uncovered_ty_params_diag ( & mut diag, ident. span , ident, local_ty) ;
495+ for ty in uncovered {
496+ let span = match ty {
497+ UncoveredTyKind :: TyParam ( ident) => ident. span ,
498+ _ => span,
499+ } ;
500+ let mut diag = tcx. dcx ( ) . struct_span_err ( span, "" ) ;
501+ decorate_uncovered_ty_diag ( & mut diag, span, ty, local_ty) ;
493502 guar. get_or_insert ( diag. emit ( ) ) ;
494503 }
504+ // This should not fail because we know that `uncovered` was non-empty at the point of
505+ // iteration since it always contains a single `Unknown` if all else fails.
495506 guar. unwrap ( )
496507 }
497508 }
498509}
499510
500- fn decorate_uncovered_ty_params_diag (
511+ fn decorate_uncovered_ty_diag (
501512 diag : & mut Diag < ' _ , impl EmissionGuarantee > ,
502513 span : Span ,
503- param : Ident ,
514+ kind : UncoveredTyKind < ' _ > ,
504515 local_ty : Option < Ty < ' _ > > ,
505516) {
517+ let descr = match kind {
518+ UncoveredTyKind :: TyParam ( ident) => Some ( ( "type parameter" , ident. to_string ( ) ) ) ,
519+ UncoveredTyKind :: OpaqueTy ( ty) => Some ( ( "opaque type" , ty. to_string ( ) ) ) ,
520+ UncoveredTyKind :: Unknown => None ,
521+ } ;
522+
506523 diag. code ( rustc_errors:: E0210 ) ;
524+ diag. span_label (
525+ span,
526+ match descr {
527+ Some ( ( kind, _) ) => format ! ( "uncovered {kind}" ) ,
528+ None => "contains an uncovered type" . into ( ) ,
529+ } ,
530+ ) ;
531+
532+ let subject = match & descr {
533+ Some ( ( kind, ty) ) => format ! ( "{kind} `{ty}`" ) ,
534+ None => "type parameters and opaque types" . into ( ) ,
535+ } ;
536+
537+ let note = "\
538+ implementing a foreign trait is only possible if \
539+ at least one of the types for which it is implemented is local";
507540
508- let note = "implementing a foreign trait is only possible if at least one of the types for which it is implemented is local" ;
509541 if let Some ( local_ty) = local_ty {
510- let msg = format ! (
511- "type parameter `{param}` must be covered by another type when it appears before the first local type (`{local_ty}`)"
542+ diag. primary_message ( format ! ( "{subject} must be covered by another type when it appears before the first local type (`{local_ty}`)" ) ) ;
543+ diag. note ( format ! ( "{note},\n and no uncovered type parameters or opaque types appear before that first local type" ) ) ;
544+ diag. note (
545+ "in this case, 'before' refers to the following order: \
546+ `impl<...> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last",
512547 ) ;
513- diag. primary_message ( msg. clone ( ) ) ;
514- diag. span_label ( span, msg) ;
515- diag. note ( format ! (
516- "{note}, and no uncovered type parameters appear before that first local type"
517- ) ) ;
518- diag. note ( "in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last" ) ;
519548 } else {
520- let msg = format ! (
521- "type parameter `{param}` must be used as the type parameter for some local type"
522- ) ;
523- diag. primary_message ( format ! ( "{msg} (e.g., `MyStruct<{param}>`)" ) ) ;
524- diag. span_label ( span, msg) ;
549+ let example = descr. map ( |( _, ty) | format ! ( " (e.g., `MyStruct<{ty}>`)" ) ) . unwrap_or_default ( ) ;
550+ diag. primary_message ( format ! (
551+ "{subject} must be used as the argument to some local type{example}"
552+ ) ) ;
525553 diag. note ( note) ;
526554 diag. note (
527- "only traits defined in the current crate can be implemented for a type parameter" ,
555+ "only traits defined in the current crate can be implemented for type parameters and opaque types"
528556 ) ;
529557 }
530558}
531559
532- struct UncoveredTyParamCollector < ' cx , ' tcx > {
560+ struct UncoveredTyCollector < ' cx , ' tcx > {
533561 infcx : & ' cx InferCtxt < ' tcx > ,
534- uncovered_params : FxIndexSet < DefId > ,
562+ uncovered : UncoveredTys < ' tcx > ,
535563}
536564
537- impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for UncoveredTyParamCollector < ' _ , ' tcx > {
565+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for UncoveredTyCollector < ' _ , ' tcx > {
538566 fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> Self :: Result {
539- if !ty. has_type_flags ( ty :: TypeFlags :: HAS_TY_INFER ) {
567+ if !ty. has_type_flags ( TypeFlags :: HAS_TY_INFER | TypeFlags :: HAS_TY_OPAQUE ) {
540568 return ;
541569 }
542- let ty:: Infer ( ty:: TyVar ( vid) ) = * ty. kind ( ) else {
543- return ty. super_visit_with ( self ) ;
544- } ;
545- let origin = self . infcx . type_var_origin ( vid) ;
546- if let Some ( def_id) = origin. param_def_id {
547- self . uncovered_params . insert ( def_id) ;
570+ match * ty. kind ( ) {
571+ ty:: Infer ( ty:: TyVar ( vid) ) => {
572+ if let Some ( def_id) = self . infcx . type_var_origin ( vid) . param_def_id {
573+ let ident = self . infcx . tcx . item_ident ( def_id) ;
574+ self . uncovered . insert ( UncoveredTyKind :: TyParam ( ident) ) ;
575+ }
576+ }
577+ // This only works with the old solver. With the next solver, alias types like opaque
578+ // types structurally normalize to an infer var that is "unresolvable" under coherence.
579+ // Furthermore, the orphan checker returns the unnormalized type in such cases (with
580+ // exception like for `Fundamental<?opaque>`) which would be Weak for TAITs and
581+ // Projection for ATPITs.
582+ // FIXME(fmease): One solution I could see working would be to reintroduce
583+ // "TypeVarOriginKind::OpaqueTy(_)" and to stop OrphanChecker from
584+ // remapping to the unnormalized type at all.
585+ // FIXME(fmease): Should we just let uncovered Opaques take precedence over
586+ // uncovered TyParams *inside* Opaques?
587+ ty:: Alias ( ty:: Opaque , alias) if !alias. has_type_flags ( TypeFlags :: HAS_TY_INFER ) => {
588+ self . uncovered . insert ( UncoveredTyKind :: OpaqueTy ( ty) ) ;
589+ }
590+ _ => ty. super_visit_with ( self ) ,
548591 }
549592 }
550593
551594 fn visit_const ( & mut self , ct : ty:: Const < ' tcx > ) -> Self :: Result {
552- if ct. has_type_flags ( ty :: TypeFlags :: HAS_TY_INFER ) {
595+ if ct. has_type_flags ( TypeFlags :: HAS_TY_INFER | TypeFlags :: HAS_TY_OPAQUE ) {
553596 ct. super_visit_with ( self )
554597 }
555598 }
556599}
600+
601+ type UncoveredTys < ' tcx > = FxIndexSet < UncoveredTyKind < ' tcx > > ;
602+
603+ #[ derive( PartialEq , Eq , Hash , Debug ) ]
604+ enum UncoveredTyKind < ' tcx > {
605+ TyParam ( Ident ) ,
606+ OpaqueTy ( Ty < ' tcx > ) ,
607+ Unknown ,
608+ }
0 commit comments