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

Commit 579a337

Browse files
committed
Normalize trait ref before orphan check & consider ty params in alias types to be uncovered
1 parent ee933f6 commit 579a337

23 files changed

+483
-63
lines changed

compiler/rustc_hir_analysis/messages.ftl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -429,13 +429,13 @@ hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$de
429429
.label = needs at most one field with non-trivial size or alignment, but has {$field_count}
430430
.labels = this field has non-zero size or requires alignment
431431
432-
hir_analysis_ty_param_first_local = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`)
433-
.label = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`)
432+
hir_analysis_ty_param_first_local = type parameter `{$param}` must be covered by another type when it appears before the first local type (`{$local_type}`)
433+
.label = type parameter `{$param}` must be covered by another type when it appears before the first local type (`{$local_type}`)
434434
.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
435435
.case_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
436436
437-
hir_analysis_ty_param_some = type parameter `{$param_ty}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param_ty}>`)
438-
.label = type parameter `{$param_ty}` must be used as the type parameter for some local type
437+
hir_analysis_ty_param_some = type parameter `{$param}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param}>`)
438+
.label = type parameter `{$param}` must be used as the type parameter for some local type
439439
.note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
440440
.only_note = only traits defined in the current crate can be implemented for a type parameter
441441

compiler/rustc_hir_analysis/src/coherence/orphan.rs

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
//! crate or pertains to a type defined in this crate.
33
44
use crate::errors;
5+
6+
use std::ops::ControlFlow;
7+
8+
use rustc_data_structures::fx::FxIndexMap;
59
use rustc_errors::ErrorGuaranteed;
6-
use rustc_hir as hir;
7-
use rustc_middle::ty::{self, AliasKind, Ty, TyCtxt, TypeVisitableExt};
10+
use rustc_middle::ty::{self, AliasKind, Ty, TyCtxt};
11+
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
812
use rustc_span::def_id::LocalDefId;
9-
use rustc_span::Span;
13+
use rustc_span::{Span, Symbol};
1014
use rustc_trait_selection::traits::{self, IsFirstInputType};
1115

1216
#[instrument(skip(tcx), level = "debug")]
@@ -23,20 +27,17 @@ pub(crate) fn orphan_check_impl(
2327
Ok(()) => {}
2428
Err(err) => {
2529
let item = tcx.hir().expect_item(impl_def_id);
26-
let hir::ItemKind::Impl(impl_) = item.kind else {
27-
bug!("{:?} is not an impl: {:?}", impl_def_id, item);
28-
};
29-
let tr = impl_.of_trait.as_ref().unwrap();
30-
let sp = tcx.def_span(impl_def_id);
30+
let impl_ = item.expect_impl();
31+
let hir_trait_ref = impl_.of_trait.as_ref().unwrap();
3132

3233
emit_orphan_check_error(
3334
tcx,
34-
sp,
35+
tcx.def_span(impl_def_id),
3536
item.span,
36-
tr.path.span,
37+
hir_trait_ref.path.span,
3738
trait_ref,
3839
impl_.self_ty.span,
39-
impl_.generics,
40+
tcx.generics_of(impl_def_id),
4041
err,
4142
)?
4243
}
@@ -277,7 +278,7 @@ fn emit_orphan_check_error<'tcx>(
277278
trait_span: Span,
278279
trait_ref: ty::TraitRef<'tcx>,
279280
self_ty_span: Span,
280-
generics: &hir::Generics<'tcx>,
281+
generics: &'tcx ty::Generics,
281282
err: traits::OrphanCheckErr<'tcx>,
282283
) -> Result<!, ErrorGuaranteed> {
283284
let self_ty = trait_ref.self_ty();
@@ -404,23 +405,48 @@ fn emit_orphan_check_error<'tcx>(
404405
};
405406
tcx.dcx().emit_err(err_struct)
406407
}
407-
traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
408-
let mut sp = sp;
409-
for param in generics.params {
410-
if param.name.ident().to_string() == param_ty.to_string() {
411-
sp = param.span;
412-
}
408+
// FIXME(fmease): The uncovered ty may contain infer vars.
409+
// 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() };
413+
uncovered_ty.visit_with(&mut collector);
414+
415+
let mut reported = None;
416+
for (param, span) in collector.uncovered_params {
417+
reported.get_or_insert(match local_type {
418+
Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
419+
span,
420+
note: (),
421+
param,
422+
local_type,
423+
}),
424+
None => tcx.dcx().emit_err(errors::TyParamSome { span, note: (), param }),
425+
});
413426
}
414427

415-
match local_type {
416-
Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
417-
span: sp,
418-
note: (),
419-
param_ty,
420-
local_type,
421-
}),
422-
None => tcx.dcx().emit_err(errors::TyParamSome { span: sp, note: (), param_ty }),
428+
struct UncoveredTyParamCollector<'tcx> {
429+
tcx: TyCtxt<'tcx>,
430+
generics: &'tcx ty::Generics,
431+
uncovered_params: FxIndexMap<Symbol, Span>,
423432
}
433+
434+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'tcx> {
435+
type BreakTy = !;
436+
437+
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)
445+
}
446+
}
447+
}
448+
449+
reported.unwrap_or_else(|| bug!("failed to find ty param in `{uncovered_ty}`"))
424450
}
425451
})
426452
}

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,20 +1328,20 @@ pub struct TyParamFirstLocal<'a> {
13281328
pub span: Span,
13291329
#[note(hir_analysis_case_note)]
13301330
pub note: (),
1331-
pub param_ty: Ty<'a>,
1331+
pub param: Symbol,
13321332
pub local_type: Ty<'a>,
13331333
}
13341334

13351335
#[derive(Diagnostic)]
13361336
#[diag(hir_analysis_ty_param_some, code = E0210)]
13371337
#[note]
1338-
pub struct TyParamSome<'a> {
1338+
pub struct TyParamSome {
13391339
#[primary_span]
13401340
#[label]
13411341
pub span: Span,
13421342
#[note(hir_analysis_only_note)]
13431343
pub note: (),
1344-
pub param_ty: Ty<'a>,
1344+
pub param: Symbol,
13451345
}
13461346

13471347
#[derive(Diagnostic)]

compiler/rustc_trait_selection/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#![feature(box_patterns)]
2121
#![feature(control_flow_enum)]
2222
#![feature(extract_if)]
23+
#![feature(if_let_guard)]
2324
#![feature(let_chains)]
2425
#![feature(option_take_if)]
2526
#![feature(never_type)]

compiler/rustc_trait_selection/src/traits/coherence.rs

Lines changed: 89 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ use crate::solve::{deeply_normalize_for_diagnostics, inspect, FulfillmentCtxt};
1212
use crate::traits::engine::TraitEngineExt as _;
1313
use crate::traits::select::IntercrateAmbiguityCause;
1414
use crate::traits::structural_normalize::StructurallyNormalizeExt;
15-
use crate::traits::NormalizeExt;
1615
use crate::traits::SkipLeakCheck;
16+
use crate::traits::{NormalizeExt, ObligationCtxt};
1717
use crate::traits::{
1818
Obligation, ObligationCause, PredicateObligation, PredicateObligations, SelectionContext,
1919
};
2020
use rustc_data_structures::fx::FxIndexSet;
2121
use rustc_errors::{DiagnosticBuilder, EmissionGuarantee};
2222
use rustc_hir::def::DefKind;
23-
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
23+
use rustc_hir::def_id::DefId;
2424
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
2525
use rustc_infer::traits::{util, TraitEngine, TraitEngineExt};
2626
use rustc_middle::traits::query::NoSolution;
@@ -598,7 +598,7 @@ pub fn trait_ref_is_local_or_fundamental<'tcx>(
598598
tcx: TyCtxt<'tcx>,
599599
trait_ref: ty::TraitRef<'tcx>,
600600
) -> bool {
601-
trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental)
601+
trait_ref.def_id.is_local() || tcx.has_attr(trait_ref.def_id, sym::fundamental)
602602
}
603603

604604
#[derive(Debug, Copy, Clone)]
@@ -630,7 +630,7 @@ pub enum OrphanCheckErr<'tcx> {
630630
/// 2. Some local type must appear in `Self`.
631631
#[instrument(level = "debug", skip(tcx), ret)]
632632
pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> {
633-
// We only except this routine to be invoked on implementations
633+
// We only accept this routine to be invoked on implementations
634634
// of a trait, not inherent implementations.
635635
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
636636
debug!(?trait_ref);
@@ -641,7 +641,35 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
641641
return Ok(());
642642
}
643643

644-
orphan_check_trait_ref::<!>(trait_ref, InCrate::Local, |ty| Ok(ty)).unwrap()
644+
orphan_check_trait_ref::<!>(trait_ref, InCrate::Local, |raw_ty| {
645+
let ty::Alias(..) = raw_ty.kind() else { return Ok(raw_ty) };
646+
647+
let infcx = tcx.infer_ctxt().intercrate(true).build();
648+
let cause = ObligationCause::dummy();
649+
650+
let args = infcx.fresh_args_for_item(cause.span, impl_def_id);
651+
let raw_ty = ty::EarlyBinder::bind(raw_ty).instantiate(tcx, args);
652+
653+
let ocx = ObligationCtxt::new(&infcx);
654+
let ty = ocx.normalize(&cause, ty::ParamEnv::empty(), raw_ty);
655+
let ty = infcx.resolve_vars_if_possible(ty);
656+
let errors = ocx.select_where_possible();
657+
if !errors.is_empty() {
658+
return Ok(raw_ty);
659+
}
660+
661+
if infcx.next_trait_solver() {
662+
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(&infcx);
663+
infcx
664+
.at(&cause, ty::ParamEnv::empty())
665+
.structurally_normalize(ty, &mut *fulfill_cx)
666+
.map(|ty| infcx.resolve_vars_if_possible(ty))
667+
.or(Ok(ty))
668+
} else {
669+
Ok(ty)
670+
}
671+
})
672+
.unwrap()
645673
}
646674

647675
/// Checks whether a trait-ref is potentially implementable by a crate.
@@ -689,6 +717,9 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
689717
/// To check that a local impl follows the orphan rules, we check it in
690718
/// InCrate::Local mode, using type parameters for the "generic" types.
691719
///
720+
/// In InCrate::Local mode the orphan check succeeds if the current crate
721+
/// is definitely allowed to implement the given trait (no false positives).
722+
///
692723
/// 2. They ground negative reasoning for coherence. If a user wants to
693724
/// write both a conditional blanket impl and a specific impl, we need to
694725
/// make sure they do not overlap. For example, if we write
@@ -707,6 +738,9 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe
707738
/// try to implement this trait-ref. To check for this, we use InCrate::Remote
708739
/// mode. That is sound because we already know all the impls from known crates.
709740
///
741+
/// In InCrate::Remote mode the orphan check succeeds if a foreign crate
742+
/// *could* implement the given trait (no false negatives).
743+
///
710744
/// 3. For non-`#[fundamental]` traits, they guarantee that parent crates can
711745
/// add "non-blanket" impls without breaking negative reasoning in dependent
712746
/// crates. This is the "rebalancing coherence" (RFC 1023) restriction.
@@ -747,16 +781,14 @@ fn orphan_check_trait_ref<'tcx, E: Debug>(
747781
Ok(match trait_ref.visit_with(&mut checker) {
748782
ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
749783
ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)) => return Err(err),
750-
ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => {
784+
ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(ty)) => {
751785
// Does there exist some local type after the `ParamTy`.
752786
checker.search_first_local_ty = true;
753-
if let Some(OrphanCheckEarlyExit::LocalTy(local_ty)) =
754-
trait_ref.visit_with(&mut checker).break_value()
755-
{
756-
Err(OrphanCheckErr::UncoveredTy(ty, Some(local_ty)))
757-
} else {
758-
Err(OrphanCheckErr::UncoveredTy(ty, None))
759-
}
787+
let local_ty = match trait_ref.visit_with(&mut checker).break_value() {
788+
Some(OrphanCheckEarlyExit::LocalTy(local_ty)) => Some(local_ty),
789+
_ => None,
790+
};
791+
Err(OrphanCheckErr::UncoveredTy(ty, local_ty))
760792
}
761793
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(_)) => Ok(()),
762794
})
@@ -791,11 +823,14 @@ where
791823
ControlFlow::Continue(())
792824
}
793825

794-
fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx, E>> {
826+
fn found_uncovered_ty_param(
827+
&mut self,
828+
t: Ty<'tcx>,
829+
) -> ControlFlow<OrphanCheckEarlyExit<'tcx, E>> {
795830
if self.search_first_local_ty {
796831
ControlFlow::Continue(())
797832
} else {
798-
ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t))
833+
ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(t))
799834
}
800835
}
801836

@@ -809,7 +844,7 @@ where
809844

810845
enum OrphanCheckEarlyExit<'tcx, E> {
811846
NormalizationFailure(E),
812-
ParamTy(Ty<'tcx>),
847+
UncoveredTyParam(Ty<'tcx>),
813848
LocalTy(Ty<'tcx>),
814849
}
815850

@@ -823,9 +858,9 @@ where
823858
}
824859

825860
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
826-
// Need to lazily normalize here in with `-Znext-solver=coherence`.
827861
let ty = match (self.lazily_normalize_ty)(ty) {
828-
Ok(ty) => ty,
862+
Ok(norm_ty) if norm_ty.is_ty_or_numeric_infer() => ty,
863+
Ok(norm_ty) => norm_ty,
829864
Err(err) => return ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)),
830865
};
831866

@@ -842,19 +877,44 @@ where
842877
| ty::Slice(..)
843878
| ty::RawPtr(..)
844879
| ty::Never
845-
| ty::Tuple(..)
846-
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) => {
847-
self.found_non_local_ty(ty)
848-
}
849-
850-
ty::Param(..) => self.found_param_ty(ty),
880+
| ty::Tuple(..) => self.found_non_local_ty(ty),
851881

852-
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match self.in_crate {
853-
InCrate::Local => self.found_non_local_ty(ty),
854-
// The inference variable might be unified with a local
855-
// type in that remote crate.
856-
InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
882+
ty::Param(..) => match self.in_crate {
883+
InCrate::Local => self.found_uncovered_ty_param(ty),
884+
InCrate::Remote => bug!("unexpected ty param"),
857885
},
886+
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => {
887+
match self.in_crate {
888+
InCrate::Local => self.found_uncovered_ty_param(ty),
889+
// The inference variable might be unified with a local
890+
// type in that remote crate.
891+
InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
892+
}
893+
}
894+
895+
ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) => {
896+
if ty.has_type_flags(ty::TypeFlags::HAS_TY_PARAM) {
897+
match self.in_crate {
898+
InCrate::Local => self.found_uncovered_ty_param(ty),
899+
InCrate::Remote => bug!("unexpected ty param"),
900+
}
901+
} else if ty.has_type_flags(
902+
ty::TypeFlags::HAS_TY_PLACEHOLDER
903+
| ty::TypeFlags::HAS_TY_BOUND
904+
| ty::TypeFlags::HAS_TY_INFER,
905+
) {
906+
match self.in_crate {
907+
InCrate::Local => self.found_uncovered_ty_param(ty),
908+
InCrate::Remote => {
909+
// The inference variable might be unified with a local
910+
// type in that remote crate.
911+
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
912+
}
913+
}
914+
} else {
915+
ControlFlow::Continue(())
916+
}
917+
}
858918

859919
// For fundamental types, we just look inside of them.
860920
ty::Ref(_, ty, _) => ty.visit_with(self),
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub trait Trait0<T, U, V> {}
2+
pub trait Trait1<T, U> {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub trait Trait {
2+
type Assoc;
3+
}

0 commit comments

Comments
 (0)