@@ -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,24 +29,28 @@ 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-
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+ // Given `impl<A, B> C<B> for D<A>`,
38+ let span = match in_self_ty {
39+ InSelfTy :: Yes => impl_. self_ty . span , // point at `D<A>`.
40+ InSelfTy :: No => hir_trait_ref. path . span , // point at `C<B>`.
41+ } ;
42+
43+ for ty in uncovered {
44+ let span = match ty {
45+ UncoveredTyKind :: TyParam ( ident) => ident. span ,
46+ UncoveredTyKind :: Unknown => span,
47+ _ => bug ! ( ) ,
48+ } ;
3949 tcx. node_span_lint (
4050 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+ item. hir_id ( ) ,
52+ span,
53+ |diag| decorate_uncovered_ty_diag ( diag, span, ty, local_ty) ,
5154 ) ;
5255 }
5356 }
@@ -295,20 +298,13 @@ pub(crate) fn orphan_check_impl(
295298 Ok ( ( ) )
296299}
297300
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`.
301+ /// Checks the coherence orphan rules for trait impl given by `impl_def_id`.
306302#[ instrument( level = "debug" , skip( tcx) , ret) ]
307303fn orphan_check < ' tcx > (
308304 tcx : TyCtxt < ' tcx > ,
309305 impl_def_id : LocalDefId ,
310306 mode : OrphanCheckMode ,
311- ) -> Result < ( ) , OrphanCheckErr < TyCtxt < ' tcx > , FxIndexSet < DefId > > > {
307+ ) -> Result < ( ) , OrphanCheckErr < TyCtxt < ' tcx > , UncoveredTys < ' tcx > > > {
312308 // We only accept this routine to be invoked on implementations
313309 // of a trait, not inherent implementations.
314310 let trait_ref = tcx. impl_trait_ref ( impl_def_id) . unwrap ( ) ;
@@ -361,15 +357,17 @@ fn orphan_check<'tcx>(
361357
362358 // (2) Try to map the remaining inference vars back to generic params.
363359 result. map_err ( |err| match err {
364- OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams { uncovered, local_ty } ) => {
360+ OrphanCheckErr :: UncoveredTy ( UncoveredTy { uncovered, in_self_ty , local_ty } ) => {
365361 let mut collector =
366- UncoveredTyParamCollector { infcx : & infcx, uncovered_params : Default :: default ( ) } ;
362+ UncoveredTyCollector { infcx : & infcx, uncovered : Default :: default ( ) } ;
367363 uncovered. visit_with ( & mut collector) ;
368- // FIXME(fmease): This is very likely reachable.
369- debug_assert ! ( !collector. uncovered_params. is_empty( ) ) ;
364+ if collector. uncovered . is_empty ( ) {
365+ collector. uncovered . insert ( UncoveredTyKind :: Unknown ) ;
366+ }
370367
371- OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams {
372- uncovered : collector. uncovered_params ,
368+ OrphanCheckErr :: UncoveredTy ( UncoveredTy {
369+ uncovered : collector. uncovered ,
370+ in_self_ty,
373371 local_ty,
374372 } )
375373 }
@@ -397,14 +395,20 @@ fn emit_orphan_check_error<'tcx>(
397395 tcx : TyCtxt < ' tcx > ,
398396 trait_ref : ty:: TraitRef < ' tcx > ,
399397 impl_def_id : LocalDefId ,
400- err : traits :: OrphanCheckErr < TyCtxt < ' tcx > , FxIndexSet < DefId > > ,
398+ err : OrphanCheckErr < TyCtxt < ' tcx > , UncoveredTys < ' tcx > > ,
401399) -> 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 ( ) ;
400+ let item = tcx. hir_expect_item ( impl_def_id) ;
401+ let impl_ = item. expect_impl ( ) ;
402+ let hir_trait_ref = impl_. of_trait . as_ref ( ) . unwrap ( ) ;
403+
404+ // Given `impl<A, B> C<B> for D<A>`,
405+ let impl_trait_ref_span = |in_self_ty| match in_self_ty {
406+ InSelfTy :: Yes => impl_. self_ty . span , // point at `D<A>`.
407+ InSelfTy :: No => hir_trait_ref. path . span , // point at `C<B>`.
408+ } ;
407409
410+ match err {
411+ OrphanCheckErr :: NonLocalInputType ( tys) => {
408412 let span = tcx. def_span ( impl_def_id) ;
409413 let mut diag = tcx. dcx ( ) . create_err ( match trait_ref. self_ty ( ) . kind ( ) {
410414 ty:: Adt ( ..) => errors:: OnlyCurrentTraits :: Outside { span, note : ( ) } ,
@@ -415,16 +419,11 @@ fn emit_orphan_check_error<'tcx>(
415419 } ) ;
416420
417421 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- } ;
422+ let span = impl_trait_ref_span ( in_self_ty) ;
423+ let is_foreign = !trait_ref. def_id . is_local ( ) && matches ! ( in_self_ty, InSelfTy :: No ) ;
423424
424425 ty = tcx. erase_regions ( ty) ;
425426
426- let is_foreign = !trait_ref. def_id . is_local ( ) && matches ! ( in_self_ty, InSelfTy :: No ) ;
427-
428427 match * ty. kind ( ) {
429428 ty:: Slice ( _) => {
430429 if is_foreign {
@@ -484,73 +483,121 @@ fn emit_orphan_check_error<'tcx>(
484483
485484 diag. emit ( )
486485 }
487- traits:: OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams { uncovered, local_ty } ) => {
486+ OrphanCheckErr :: UncoveredTy ( UncoveredTy { uncovered, in_self_ty, local_ty } ) => {
487+ let span = impl_trait_ref_span ( in_self_ty) ;
488+
488489 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) ;
490+ for ty in uncovered {
491+ let span = match ty {
492+ UncoveredTyKind :: TyParam ( ident) => ident. span ,
493+ _ => span,
494+ } ;
495+ let mut diag = tcx. dcx ( ) . struct_span_err ( span, "" ) ;
496+ decorate_uncovered_ty_diag ( & mut diag, span, ty, local_ty) ;
493497 guar. get_or_insert ( diag. emit ( ) ) ;
494498 }
499+ // This should not fail because we know that `uncovered` was non-empty at the point of
500+ // iteration since it always contains a single `Unknown` if all else fails.
495501 guar. unwrap ( )
496502 }
497503 }
498504}
499505
500- fn decorate_uncovered_ty_params_diag (
506+ fn decorate_uncovered_ty_diag (
501507 diag : & mut Diag < ' _ , impl EmissionGuarantee > ,
502508 span : Span ,
503- param : Ident ,
509+ kind : UncoveredTyKind < ' _ > ,
504510 local_ty : Option < Ty < ' _ > > ,
505511) {
512+ let descr = match kind {
513+ UncoveredTyKind :: TyParam ( ident) => Some ( ( "type parameter" , ident. to_string ( ) ) ) ,
514+ UncoveredTyKind :: OpaqueTy ( ty) => Some ( ( "opaque type" , ty. to_string ( ) ) ) ,
515+ UncoveredTyKind :: Unknown => None ,
516+ } ;
517+
506518 diag. code ( rustc_errors:: E0210 ) ;
519+ diag. span_label (
520+ span,
521+ match descr {
522+ Some ( ( kind, _) ) => format ! ( "uncovered {kind}" ) ,
523+ None => "contains an uncovered type" . into ( ) ,
524+ } ,
525+ ) ;
526+
527+ let subject = match & descr {
528+ Some ( ( kind, ty) ) => format ! ( "{kind} `{ty}`" ) ,
529+ None => "type parameters and opaque types" . into ( ) ,
530+ } ;
531+
532+ let note = "\
533+ implementing a foreign trait is only possible if \
534+ at least one of the types for which it is implemented is local";
507535
508- let note = "implementing a foreign trait is only possible if at least one of the types for which it is implemented is local" ;
509536 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}`)"
537+ diag. primary_message ( format ! ( "{subject} must be covered by another type when it appears before the first local type (`{local_ty}`)" ) ) ;
538+ diag. note ( format ! ( "{note},\n and no uncovered type parameters or opaque types appear before that first local type" ) ) ;
539+ diag. note (
540+ "in this case, 'before' refers to the following order: \
541+ `impl<...> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last",
512542 ) ;
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" ) ;
519543 } 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) ;
544+ let example = descr. map ( |( _, ty) | format ! ( " (e.g., `MyStruct<{ty}>`)" ) ) . unwrap_or_default ( ) ;
545+ diag. primary_message ( format ! (
546+ "{subject} must be used as the argument to some local type{example}"
547+ ) ) ;
525548 diag. note ( note) ;
526549 diag. note (
527- "only traits defined in the current crate can be implemented for a type parameter" ,
550+ "only traits defined in the current crate can be implemented for type parameters and opaque types"
528551 ) ;
529552 }
530553}
531554
532- struct UncoveredTyParamCollector < ' cx , ' tcx > {
555+ struct UncoveredTyCollector < ' cx , ' tcx > {
533556 infcx : & ' cx InferCtxt < ' tcx > ,
534- uncovered_params : FxIndexSet < DefId > ,
557+ uncovered : UncoveredTys < ' tcx > ,
535558}
536559
537- impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for UncoveredTyParamCollector < ' _ , ' tcx > {
560+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for UncoveredTyCollector < ' _ , ' tcx > {
538561 fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> Self :: Result {
539- if !ty. has_type_flags ( ty :: TypeFlags :: HAS_TY_INFER ) {
562+ if !ty. has_type_flags ( TypeFlags :: HAS_TY_INFER | TypeFlags :: HAS_TY_OPAQUE ) {
540563 return ;
541564 }
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) ;
565+ match * ty. kind ( ) {
566+ ty:: Infer ( ty:: TyVar ( vid) ) => {
567+ if let Some ( def_id) = self . infcx . type_var_origin ( vid) . param_def_id {
568+ let ident = self . infcx . tcx . item_ident ( def_id) ;
569+ self . uncovered . insert ( UncoveredTyKind :: TyParam ( ident) ) ;
570+ }
571+ }
572+ // This only works with the old solver. With the next solver, alias types like opaque
573+ // types structurally normalize to an infer var that is "unresolvable" under coherence.
574+ // Furthermore, the orphan checker returns the unnormalized type in such cases (with
575+ // exception like for `Fundamental<?opaque>`) which would be Weak for TAITs and
576+ // Projection for ATPITs.
577+ // FIXME(fmease): One solution I could see working would be to reintroduce
578+ // "TypeVarOriginKind::OpaqueTy(_)" and to stop OrphanChecker from
579+ // remapping to the unnormalized type at all.
580+ // FIXME(fmease): Should we just let uncovered Opaques take precedence over
581+ // uncovered TyParams *inside* Opaques?
582+ ty:: Alias ( ty:: Opaque , alias) if !alias. has_type_flags ( TypeFlags :: HAS_TY_INFER ) => {
583+ self . uncovered . insert ( UncoveredTyKind :: OpaqueTy ( ty) ) ;
584+ }
585+ _ => ty. super_visit_with ( self ) ,
548586 }
549587 }
550588
551589 fn visit_const ( & mut self , ct : ty:: Const < ' tcx > ) -> Self :: Result {
552- if ct. has_type_flags ( ty :: TypeFlags :: HAS_TY_INFER ) {
590+ if ct. has_type_flags ( TypeFlags :: HAS_TY_INFER | TypeFlags :: HAS_TY_OPAQUE ) {
553591 ct. super_visit_with ( self )
554592 }
555593 }
556594}
595+
596+ type UncoveredTys < ' tcx > = FxIndexSet < UncoveredTyKind < ' tcx > > ;
597+
598+ #[ derive( PartialEq , Eq , Hash , Debug ) ]
599+ enum UncoveredTyKind < ' tcx > {
600+ TyParam ( Ident ) ,
601+ OpaqueTy ( Ty < ' tcx > ) ,
602+ Unknown ,
603+ }
0 commit comments