Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 55d96b3

Browse files
committed
[hack] orphan checks: diagnostics: support infer vars in uncovered tys
1 parent 579a337 commit 55d96b3

File tree

5 files changed

+103
-64
lines changed

5 files changed

+103
-64
lines changed

compiler/rustc_hir_analysis/src/coherence/orphan.rs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use std::ops::ControlFlow;
77

88
use rustc_data_structures::fx::FxIndexMap;
99
use rustc_errors::ErrorGuaranteed;
10+
use rustc_infer::infer::type_variable::TypeVariableOriginKind;
11+
use rustc_infer::infer::InferCtxt;
1012
use rustc_middle::ty::{self, AliasKind, Ty, TyCtxt};
1113
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
1214
use rustc_span::def_id::LocalDefId;
@@ -407,9 +409,13 @@ fn emit_orphan_check_error<'tcx>(
407409
}
408410
// FIXME(fmease): The uncovered ty may contain infer vars.
409411
// Somwhere we need to remap them to ty params.
410-
traits::OrphanCheckErr::UncoveredTy(uncovered_ty, local_type) => {
411-
let mut collector =
412-
UncoveredTyParamCollector { tcx, generics, uncovered_params: Default::default() };
412+
traits::OrphanCheckErr::UncoveredTy(uncovered_ty, infcx, local_type) => {
413+
let mut collector = UncoveredTyParamCollector {
414+
tcx,
415+
infcx,
416+
generics,
417+
uncovered_params: Default::default(),
418+
};
413419
uncovered_ty.visit_with(&mut collector);
414420

415421
let mut reported = None;
@@ -427,22 +433,44 @@ fn emit_orphan_check_error<'tcx>(
427433

428434
struct UncoveredTyParamCollector<'tcx> {
429435
tcx: TyCtxt<'tcx>,
436+
infcx: Option<Box<InferCtxt<'tcx>>>,
430437
generics: &'tcx ty::Generics,
431438
uncovered_params: FxIndexMap<Symbol, Span>,
432439
}
433440

441+
impl<'tcx> UncoveredTyParamCollector<'tcx> {
442+
fn add_uncovered_param_ty(&mut self, index: u32) {
443+
let param_def = self.generics.param_at(index as _, self.tcx);
444+
let span = self.tcx.def_ident_span(param_def.def_id).unwrap();
445+
self.uncovered_params.insert(param_def.name, span);
446+
}
447+
}
448+
434449
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'tcx> {
435450
type BreakTy = !;
436451

437452
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
438-
if let ty::Param(param_ty) = *ty.kind() {
439-
let param_def = self.generics.param_at(param_ty.index as _, self.tcx);
440-
let span = self.tcx.def_ident_span(param_def.def_id).unwrap();
441-
self.uncovered_params.insert(param_def.name, span);
442-
ControlFlow::Continue(())
443-
} else {
444-
ty.super_visit_with(self)
453+
match *ty.kind() {
454+
ty::Param(param_ty) => {
455+
self.add_uncovered_param_ty(param_ty.index);
456+
return ControlFlow::Continue(());
457+
}
458+
ty::Infer(ty::TyVar(_)) => {
459+
if let Some(infcx) = &self.infcx
460+
&& let Some(origin) = infcx.type_var_origin(ty)
461+
&& let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) =
462+
origin.kind
463+
&& let Some(index) =
464+
self.generics.param_def_id_to_index(self.tcx, def_id)
465+
{
466+
self.add_uncovered_param_ty(index);
467+
return ControlFlow::Continue(());
468+
}
469+
}
470+
_ => {}
445471
}
472+
473+
ty.super_visit_with(self)
446474
}
447475
}
448476

compiler/rustc_trait_selection/src/traits/coherence.rs

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,11 @@ pub fn trait_ref_is_knowable<'tcx, E: Debug>(
564564
trait_ref: ty::TraitRef<'tcx>,
565565
mut lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
566566
) -> Result<Result<(), Conflict>, E> {
567-
if orphan_check_trait_ref(trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok() {
567+
if orphan_check_trait_ref(trait_ref, InCrate::Remote, |ty| {
568+
lazily_normalize_ty(ty).map(|ty| (ty, None))
569+
})?
570+
.is_ok()
571+
{
568572
// A downstream or cousin crate is allowed to implement some
569573
// generic parameters of this trait-ref.
570574
return Ok(Err(Conflict::Downstream));
@@ -587,7 +591,11 @@ pub fn trait_ref_is_knowable<'tcx, E: Debug>(
587591
// and if we are an intermediate owner, then we don't care
588592
// about future-compatibility, which means that we're OK if
589593
// we are an owner.
590-
if orphan_check_trait_ref(trait_ref, InCrate::Local, &mut lazily_normalize_ty)?.is_ok() {
594+
if orphan_check_trait_ref(trait_ref, InCrate::Local, |ty| {
595+
lazily_normalize_ty(ty).map(|ty| (ty, None))
596+
})?
597+
.is_ok()
598+
{
591599
Ok(Ok(()))
592600
} else {
593601
Ok(Err(Conflict::Upstream))
@@ -616,10 +624,20 @@ impl From<bool> for IsFirstInputType {
616624
}
617625
}
618626

619-
#[derive(Debug)]
620627
pub enum OrphanCheckErr<'tcx> {
621628
NonLocalInputType(Vec<(Ty<'tcx>, IsFirstInputType)>),
622-
UncoveredTy(Ty<'tcx>, Option<Ty<'tcx>>),
629+
UncoveredTy(Ty<'tcx>, Option<Box<InferCtxt<'tcx>>>, Option<Ty<'tcx>>),
630+
}
631+
632+
impl<'tcx> Debug for OrphanCheckErr<'tcx> {
633+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
634+
match self {
635+
Self::NonLocalInputType(ty) => f.debug_tuple("NonLocalInputType").field(ty).finish(),
636+
Self::UncoveredTy(ty, _, local_ty) => {
637+
f.debug_tuple("UncoveredTy").field(ty).field(local_ty).finish()
638+
}
639+
}
640+
}
623641
}
624642

625643
/// Checks the coherence orphan rules. `impl_def_id` should be the
@@ -642,7 +660,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
642660
}
643661

644662
orphan_check_trait_ref::<!>(trait_ref, InCrate::Local, |raw_ty| {
645-
let ty::Alias(..) = raw_ty.kind() else { return Ok(raw_ty) };
663+
let ty::Alias(..) = raw_ty.kind() else { return Ok((raw_ty, None)) };
646664

647665
let infcx = tcx.infer_ctxt().intercrate(true).build();
648666
let cause = ObligationCause::dummy();
@@ -655,19 +673,21 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
655673
let ty = infcx.resolve_vars_if_possible(ty);
656674
let errors = ocx.select_where_possible();
657675
if !errors.is_empty() {
658-
return Ok(raw_ty);
676+
return Ok((raw_ty, Some(Box::new(infcx))));
659677
}
660678

661-
if infcx.next_trait_solver() {
679+
let ty = if infcx.next_trait_solver() {
662680
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(&infcx);
663681
infcx
664682
.at(&cause, ty::ParamEnv::empty())
665683
.structurally_normalize(ty, &mut *fulfill_cx)
666684
.map(|ty| infcx.resolve_vars_if_possible(ty))
667-
.or(Ok(ty))
685+
.unwrap_or(ty)
668686
} else {
669-
Ok(ty)
670-
}
687+
ty
688+
};
689+
690+
Ok((ty, Some(Box::new(infcx))))
671691
})
672692
.unwrap()
673693
}
@@ -768,7 +788,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
768788
fn orphan_check_trait_ref<'tcx, E: Debug>(
769789
trait_ref: ty::TraitRef<'tcx>,
770790
in_crate: InCrate,
771-
lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
791+
lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<(Ty<'tcx>, Option<Box<InferCtxt<'tcx>>>), E>,
772792
) -> Result<Result<(), OrphanCheckErr<'tcx>>, E> {
773793
if trait_ref.has_infer() && trait_ref.has_param() {
774794
bug!(
@@ -781,14 +801,14 @@ fn orphan_check_trait_ref<'tcx, E: Debug>(
781801
Ok(match trait_ref.visit_with(&mut checker) {
782802
ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
783803
ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)) => return Err(err),
784-
ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(ty)) => {
804+
ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(ty, infcx)) => {
785805
// Does there exist some local type after the `ParamTy`.
786806
checker.search_first_local_ty = true;
787807
let local_ty = match trait_ref.visit_with(&mut checker).break_value() {
788808
Some(OrphanCheckEarlyExit::LocalTy(local_ty)) => Some(local_ty),
789809
_ => None,
790810
};
791-
Err(OrphanCheckErr::UncoveredTy(ty, local_ty))
811+
Err(OrphanCheckErr::UncoveredTy(ty, infcx, local_ty))
792812
}
793813
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(_)) => Ok(()),
794814
})
@@ -806,7 +826,7 @@ struct OrphanChecker<'tcx, F> {
806826

807827
impl<'tcx, F, E> OrphanChecker<'tcx, F>
808828
where
809-
F: FnOnce(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
829+
F: FnOnce(Ty<'tcx>) -> Result<(Ty<'tcx>, Option<Box<InferCtxt<'tcx>>>), E>,
810830
{
811831
fn new(in_crate: InCrate, lazily_normalize_ty: F) -> Self {
812832
OrphanChecker {
@@ -826,11 +846,12 @@ where
826846
fn found_uncovered_ty_param(
827847
&mut self,
828848
t: Ty<'tcx>,
849+
infcx: Option<Box<InferCtxt<'tcx>>>,
829850
) -> ControlFlow<OrphanCheckEarlyExit<'tcx, E>> {
830851
if self.search_first_local_ty {
831852
ControlFlow::Continue(())
832853
} else {
833-
ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(t))
854+
ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(t, infcx))
834855
}
835856
}
836857

@@ -844,23 +865,24 @@ where
844865

845866
enum OrphanCheckEarlyExit<'tcx, E> {
846867
NormalizationFailure(E),
847-
UncoveredTyParam(Ty<'tcx>),
868+
UncoveredTyParam(Ty<'tcx>, Option<Box<InferCtxt<'tcx>>>),
848869
LocalTy(Ty<'tcx>),
849870
}
850871

851872
impl<'tcx, F, E> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx, F>
852873
where
853-
F: FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
874+
F: FnMut(Ty<'tcx>) -> Result<(Ty<'tcx>, Option<Box<InferCtxt<'tcx>>>), E>,
854875
{
855876
type BreakTy = OrphanCheckEarlyExit<'tcx, E>;
856877
fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
857878
ControlFlow::Continue(())
858879
}
859880

860881
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
861-
let ty = match (self.lazily_normalize_ty)(ty) {
862-
Ok(norm_ty) if norm_ty.is_ty_or_numeric_infer() => ty,
863-
Ok(norm_ty) => norm_ty,
882+
let (ty, infcx) = match (self.lazily_normalize_ty)(ty) {
883+
Ok((norm_ty, infcx)) => {
884+
(if norm_ty.is_ty_or_numeric_infer() { ty } else { norm_ty }, infcx)
885+
}
864886
Err(err) => return ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)),
865887
};
866888

@@ -880,12 +902,12 @@ where
880902
| ty::Tuple(..) => self.found_non_local_ty(ty),
881903

882904
ty::Param(..) => match self.in_crate {
883-
InCrate::Local => self.found_uncovered_ty_param(ty),
905+
InCrate::Local => self.found_uncovered_ty_param(ty, infcx),
884906
InCrate::Remote => bug!("unexpected ty param"),
885907
},
886908
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => {
887909
match self.in_crate {
888-
InCrate::Local => self.found_uncovered_ty_param(ty),
910+
InCrate::Local => self.found_uncovered_ty_param(ty, infcx),
889911
// The inference variable might be unified with a local
890912
// type in that remote crate.
891913
InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
@@ -895,7 +917,7 @@ where
895917
ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) => {
896918
if ty.has_type_flags(ty::TypeFlags::HAS_TY_PARAM) {
897919
match self.in_crate {
898-
InCrate::Local => self.found_uncovered_ty_param(ty),
920+
InCrate::Local => self.found_uncovered_ty_param(ty, infcx),
899921
InCrate::Remote => bug!("unexpected ty param"),
900922
}
901923
} else if ty.has_type_flags(
@@ -904,7 +926,7 @@ where
904926
| ty::TypeFlags::HAS_TY_INFER,
905927
) {
906928
match self.in_crate {
907-
InCrate::Local => self.found_uncovered_ty_param(ty),
929+
InCrate::Local => self.found_uncovered_ty_param(ty, infcx),
908930
InCrate::Remote => {
909931
// The inference variable might be unified with a local
910932
// type in that remote crate.
Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
error: internal compiler error: compiler/rustc_hir_analysis/src/coherence/orphan.rs:449:40: failed to find ty param in `<Wrapper<_> as Discard>::Output`
1+
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
2+
--> $DIR/orphan-check-projections-unsat-bounds.rs:28:6
3+
|
4+
LL | impl<T> foreign::Trait1<LocalTy, T> for <Wrapper<T> as Discard>::Output
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
6+
|
7+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
8+
= 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
29

3-
thread 'rustc' panicked at compiler/rustc_middle/src/util/bug.rs:35:44:
4-
Box<dyn Any>
5-
stack backtrace:
6-
7-
query stack during panic:
8-
#0 [orphan_check_impl] checking whether impl `<impl at $DIR/orphan-check-projections-unsat-bounds.rs:38:1: 40:22>` follows the orphan rules
9-
#1 [coherent_trait] coherence checking all impls of trait `parametrized_trait::Trait1`
10-
#2 [analysis] running analysis passes on this crate
11-
end of query stack
1210
error: aborting due to 1 previous error
1311

12+
For more information about this error, try `rustc --explain E0210`.
Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
error: internal compiler error: compiler/rustc_hir_analysis/src/coherence/orphan.rs:449:40: failed to find ty param in `<Wrapper<_> as Discard>::Output`
1+
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
2+
--> $DIR/orphan-check-projections-unsat-bounds.rs:28:6
3+
|
4+
LL | impl<T> foreign::Trait1<LocalTy, T> for <Wrapper<T> as Discard>::Output
5+
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalTy`)
6+
|
7+
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
8+
= 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
29

3-
thread 'rustc' panicked at compiler/rustc_middle/src/util/bug.rs:35:44:
4-
Box<dyn Any>
5-
stack backtrace:
6-
7-
query stack during panic:
8-
#0 [orphan_check_impl] checking whether impl `<impl at $DIR/orphan-check-projections-unsat-bounds.rs:38:1: 40:22>` follows the orphan rules
9-
#1 [coherent_trait] coherence checking all impls of trait `parametrized_trait::Trait1`
10-
#2 [analysis] running analysis passes on this crate
11-
end of query stack
1210
error: aborting due to 1 previous error
1311

12+
For more information about this error, try `rustc --explain E0210`.

tests/ui/coherence/orphan-check-projections-unsat-bounds.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,6 @@
44
// Therefore it may fail while normalization outside of orphan checking
55
// succeeds, e.g. due to unsatisfied bounds.
66

7-
//@ known-bug: unknown
8-
//@ failure-status: 101
9-
//@ normalize-stderr-test: "DefId\(.*?\]::" -> "DefId("
10-
//@ normalize-stderr-test: "(?m)note: we would appreciate a bug report.*\n\n" -> ""
11-
//@ normalize-stderr-test: "(?m)note: rustc.*running on.*\n\n" -> ""
12-
//@ normalize-stderr-test: "(?m)note: compiler flags.*\n\n" -> ""
13-
//@ normalize-stderr-test: "(?m)note: delayed at.*$" -> ""
14-
//@ normalize-stderr-test: "(?m)^ *\d+: .*\n" -> ""
15-
//@ normalize-stderr-test: "(?m)^ *at .*\n" -> ""
16-
177
//@ revisions: classic next
188
//@[next] compile-flags: -Znext-solver
199

@@ -36,6 +26,7 @@ where
3626
struct LocalTy;
3727

3828
impl<T> foreign::Trait1<LocalTy, T> for <Wrapper<T> as Discard>::Output
29+
//~^ ERROR type parameter `T` must be covered by another type
3930
where
4031
Wrapper<T>: Bound
4132
{}

0 commit comments

Comments
 (0)