@@ -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 ( _) => {
@@ -291,20 +299,13 @@ pub(crate) fn orphan_check_impl(
291299 Ok ( ( ) )
292300}
293301
294- /// Checks the coherence orphan rules.
295- ///
296- /// `impl_def_id` should be the `DefId` of a trait impl.
297- ///
298- /// To pass, either the trait must be local, or else two conditions must be satisfied:
299- ///
300- /// 1. All type parameters in `Self` must be "covered" by some local type constructor.
301- /// 2. Some local type must appear in `Self`.
302+ /// Checks the coherence orphan rules for trait impl given by `impl_def_id`.
302303#[ instrument( level = "debug" , skip( tcx) , ret) ]
303304fn orphan_check < ' tcx > (
304305 tcx : TyCtxt < ' tcx > ,
305306 impl_def_id : LocalDefId ,
306307 mode : OrphanCheckMode ,
307- ) -> Result < ( ) , OrphanCheckErr < TyCtxt < ' tcx > , FxIndexSet < DefId > > > {
308+ ) -> Result < ( ) , OrphanCheckErr < TyCtxt < ' tcx > , UncoveredTys < ' tcx > > > {
308309 // We only accept this routine to be invoked on implementations
309310 // of a trait, not inherent implementations.
310311 let trait_ref = tcx. impl_trait_ref ( impl_def_id) ;
@@ -357,15 +358,17 @@ fn orphan_check<'tcx>(
357358
358359 // (2) Try to map the remaining inference vars back to generic params.
359360 result. map_err ( |err| match err {
360- OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams { uncovered, local_ty } ) => {
361+ OrphanCheckErr :: UncoveredTy ( UncoveredTy { uncovered, in_self_ty , local_ty } ) => {
361362 let mut collector =
362- UncoveredTyParamCollector { infcx : & infcx, uncovered_params : Default :: default ( ) } ;
363+ UncoveredTyCollector { infcx : & infcx, uncovered : Default :: default ( ) } ;
363364 uncovered. visit_with ( & mut collector) ;
364- // FIXME(fmease): This is very likely reachable.
365- debug_assert ! ( !collector. uncovered_params. is_empty( ) ) ;
365+ if collector. uncovered . is_empty ( ) {
366+ collector. uncovered . insert ( UncoveredTyKind :: Unknown ) ;
367+ }
366368
367- OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams {
368- uncovered : collector. uncovered_params ,
369+ OrphanCheckErr :: UncoveredTy ( UncoveredTy {
370+ uncovered : collector. uncovered ,
371+ in_self_ty,
369372 local_ty,
370373 } )
371374 }
@@ -393,14 +396,20 @@ fn emit_orphan_check_error<'tcx>(
393396 tcx : TyCtxt < ' tcx > ,
394397 trait_ref : ty:: TraitRef < ' tcx > ,
395398 impl_def_id : LocalDefId ,
396- err : traits :: OrphanCheckErr < TyCtxt < ' tcx > , FxIndexSet < DefId > > ,
399+ err : OrphanCheckErr < TyCtxt < ' tcx > , UncoveredTys < ' tcx > > ,
397400) -> ErrorGuaranteed {
398- match err {
399- traits:: OrphanCheckErr :: NonLocalInputType ( tys) => {
400- let item = tcx. hir_expect_item ( impl_def_id) ;
401- let impl_ = item. expect_impl ( ) ;
402- let of_trait = impl_. of_trait . unwrap ( ) ;
401+ let item = tcx. hir_expect_item ( impl_def_id) ;
402+ let impl_ = item. expect_impl ( ) ;
403+ let of_trait = impl_. of_trait . unwrap ( ) ;
404+
405+ // Given `impl<A, B> C<B> for D<A>`,
406+ let impl_trait_ref_span = |in_self_ty| match in_self_ty {
407+ InSelfTy :: Yes => impl_. self_ty . span , // point at `D<A>`.
408+ InSelfTy :: No => of_trait. trait_ref . path . span , // point at `C<B>`.
409+ } ;
403410
411+ match err {
412+ OrphanCheckErr :: NonLocalInputType ( tys) => {
404413 let span = tcx. def_span ( impl_def_id) ;
405414 let mut diag = tcx. dcx ( ) . create_err ( match trait_ref. self_ty ( ) . kind ( ) {
406415 ty:: Adt ( ..) => errors:: OnlyCurrentTraits :: Outside { span, note : ( ) } ,
@@ -411,16 +420,12 @@ fn emit_orphan_check_error<'tcx>(
411420 } ) ;
412421
413422 for & ( mut ty, in_self_ty) in & tys {
414- // Given `impl<A, B> C<B> for D<A>`,
415- let span = match in_self_ty {
416- InSelfTy :: Yes => impl_. self_ty . span , // point at `D<A>`.
417- InSelfTy :: No => of_trait. trait_ref . path . span , // point at `C<B>`.
418- } ;
423+ let span = impl_trait_ref_span ( in_self_ty) ;
424+ let is_foreign =
425+ !of_trait. trait_ref . def_id . is_local ( ) && matches ! ( in_self_ty, InSelfTy :: No ) ;
419426
420427 ty = tcx. erase_and_anonymize_regions ( ty) ;
421428
422- let is_foreign = !trait_ref. def_id . is_local ( ) && matches ! ( in_self_ty, InSelfTy :: No ) ;
423-
424429 match * ty. kind ( ) {
425430 ty:: Slice ( _) => {
426431 if is_foreign {
@@ -480,73 +485,121 @@ fn emit_orphan_check_error<'tcx>(
480485
481486 diag. emit ( )
482487 }
483- traits:: OrphanCheckErr :: UncoveredTyParams ( UncoveredTyParams { uncovered, local_ty } ) => {
488+ OrphanCheckErr :: UncoveredTy ( UncoveredTy { uncovered, in_self_ty, local_ty } ) => {
489+ let span = impl_trait_ref_span ( in_self_ty) ;
490+
484491 let mut guar = None ;
485- for param_def_id in uncovered {
486- let ident = tcx. item_ident ( param_def_id) ;
487- let mut diag = tcx. dcx ( ) . struct_span_err ( ident. span , "" ) ;
488- decorate_uncovered_ty_params_diag ( & mut diag, ident. span , ident, local_ty) ;
492+ for ty in uncovered {
493+ let span = match ty {
494+ UncoveredTyKind :: TyParam ( ident) => ident. span ,
495+ _ => span,
496+ } ;
497+ let mut diag = tcx. dcx ( ) . struct_span_err ( span, "" ) ;
498+ decorate_uncovered_ty_diag ( & mut diag, span, ty, local_ty) ;
489499 guar. get_or_insert ( diag. emit ( ) ) ;
490500 }
501+ // This should not fail because we know that `uncovered` was non-empty at the point of
502+ // iteration since it always contains a single `Unknown` if all else fails.
491503 guar. unwrap ( )
492504 }
493505 }
494506}
495507
496- fn decorate_uncovered_ty_params_diag (
508+ fn decorate_uncovered_ty_diag (
497509 diag : & mut Diag < ' _ , impl EmissionGuarantee > ,
498510 span : Span ,
499- param : Ident ,
511+ kind : UncoveredTyKind < ' _ > ,
500512 local_ty : Option < Ty < ' _ > > ,
501513) {
514+ let descr = match kind {
515+ UncoveredTyKind :: TyParam ( ident) => Some ( ( "type parameter" , ident. to_string ( ) ) ) ,
516+ UncoveredTyKind :: OpaqueTy ( ty) => Some ( ( "opaque type" , ty. to_string ( ) ) ) ,
517+ UncoveredTyKind :: Unknown => None ,
518+ } ;
519+
502520 diag. code ( rustc_errors:: E0210 ) ;
521+ diag. span_label (
522+ span,
523+ match descr {
524+ Some ( ( kind, _) ) => format ! ( "uncovered {kind}" ) ,
525+ None => "contains an uncovered type" . into ( ) ,
526+ } ,
527+ ) ;
528+
529+ let subject = match & descr {
530+ Some ( ( kind, ty) ) => format ! ( "{kind} `{ty}`" ) ,
531+ None => "type parameters and opaque types" . into ( ) ,
532+ } ;
533+
534+ let note = "\
535+ implementing a foreign trait is only possible if \
536+ at least one of the types for which it is implemented is local";
503537
504- let note = "implementing a foreign trait is only possible if at least one of the types for which it is implemented is local" ;
505538 if let Some ( local_ty) = local_ty {
506- let msg = format ! (
507- "type parameter `{param}` must be covered by another type when it appears before the first local type (`{local_ty}`)"
539+ diag. primary_message ( format ! ( "{subject} must be covered by another type when it appears before the first local type (`{local_ty}`)" ) ) ;
540+ diag. note ( format ! ( "{note},\n and no uncovered type parameters or opaque types appear before that first local type" ) ) ;
541+ diag. note (
542+ "in this case, 'before' refers to the following order: \
543+ `impl<...> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last",
508544 ) ;
509- diag. primary_message ( msg. clone ( ) ) ;
510- diag. span_label ( span, msg) ;
511- diag. note ( format ! (
512- "{note}, and no uncovered type parameters appear before that first local type"
513- ) ) ;
514- 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" ) ;
515545 } else {
516- let msg = format ! (
517- "type parameter `{param}` must be used as the type parameter for some local type"
518- ) ;
519- diag. primary_message ( format ! ( "{msg} (e.g., `MyStruct<{param}>`)" ) ) ;
520- diag. span_label ( span, msg) ;
546+ let example = descr. map ( |( _, ty) | format ! ( " (e.g., `MyStruct<{ty}>`)" ) ) . unwrap_or_default ( ) ;
547+ diag. primary_message ( format ! (
548+ "{subject} must be used as the argument to some local type{example}"
549+ ) ) ;
521550 diag. note ( note) ;
522551 diag. note (
523- "only traits defined in the current crate can be implemented for a type parameter" ,
552+ "only traits defined in the current crate can be implemented for type parameters and opaque types"
524553 ) ;
525554 }
526555}
527556
528- struct UncoveredTyParamCollector < ' cx , ' tcx > {
557+ struct UncoveredTyCollector < ' cx , ' tcx > {
529558 infcx : & ' cx InferCtxt < ' tcx > ,
530- uncovered_params : FxIndexSet < DefId > ,
559+ uncovered : UncoveredTys < ' tcx > ,
531560}
532561
533- impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for UncoveredTyParamCollector < ' _ , ' tcx > {
562+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for UncoveredTyCollector < ' _ , ' tcx > {
534563 fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> Self :: Result {
535- if !ty. has_type_flags ( ty :: TypeFlags :: HAS_TY_INFER ) {
564+ if !ty. has_type_flags ( TypeFlags :: HAS_TY_INFER | TypeFlags :: HAS_TY_OPAQUE ) {
536565 return ;
537566 }
538- let ty:: Infer ( ty:: TyVar ( vid) ) = * ty. kind ( ) else {
539- return ty. super_visit_with ( self ) ;
540- } ;
541- let origin = self . infcx . type_var_origin ( vid) ;
542- if let Some ( def_id) = origin. param_def_id {
543- self . uncovered_params . insert ( def_id) ;
567+ match * ty. kind ( ) {
568+ ty:: Infer ( ty:: TyVar ( vid) ) => {
569+ if let Some ( def_id) = self . infcx . type_var_origin ( vid) . param_def_id {
570+ let ident = self . infcx . tcx . item_ident ( def_id) ;
571+ self . uncovered . insert ( UncoveredTyKind :: TyParam ( ident) ) ;
572+ }
573+ }
574+ // This only works with the old solver. With the next solver, alias types like opaque
575+ // types structurally normalize to an infer var that is "unresolvable" under coherence.
576+ // Furthermore, the orphan checker returns the unnormalized type in such cases (with
577+ // exception like for `Fundamental<?opaque>`) which would be Weak for TAITs and
578+ // Projection for ATPITs.
579+ // FIXME(fmease): One solution I could see working would be to reintroduce
580+ // "TypeVarOriginKind::OpaqueTy(_)" and to stop OrphanChecker from
581+ // remapping to the unnormalized type at all.
582+ // FIXME(fmease): Should we just let uncovered Opaques take precedence over
583+ // uncovered TyParams *inside* Opaques?
584+ ty:: Alias ( ty:: Opaque , alias) if !alias. has_type_flags ( TypeFlags :: HAS_TY_INFER ) => {
585+ self . uncovered . insert ( UncoveredTyKind :: OpaqueTy ( ty) ) ;
586+ }
587+ _ => ty. super_visit_with ( self ) ,
544588 }
545589 }
546590
547591 fn visit_const ( & mut self , ct : ty:: Const < ' tcx > ) -> Self :: Result {
548- if ct. has_type_flags ( ty :: TypeFlags :: HAS_TY_INFER ) {
592+ if ct. has_type_flags ( TypeFlags :: HAS_TY_INFER | TypeFlags :: HAS_TY_OPAQUE ) {
549593 ct. super_visit_with ( self )
550594 }
551595 }
552596}
597+
598+ type UncoveredTys < ' tcx > = FxIndexSet < UncoveredTyKind < ' tcx > > ;
599+
600+ #[ derive( PartialEq , Eq , Hash , Debug ) ]
601+ enum UncoveredTyKind < ' tcx > {
602+ TyParam ( Ident ) ,
603+ OpaqueTy ( Ty < ' tcx > ) ,
604+ Unknown ,
605+ }
0 commit comments