Skip to content

Commit 575e416

Browse files
committed
Auto merge of rust-lang#117164 - fmease:orphan-norm, r=<try>
Normalize trait ref before orphan check & consider ty params in alias types to be uncovered Fixes rust-lang#99554, fixes rust-lang/types-team#104. Supersedes rust-lang#100555. r? lcnr
2 parents 829308e + 55d96b3 commit 575e416

23 files changed

+529
-70
lines changed

compiler/rustc_hir_analysis/messages.ftl

+4-4
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

+79-25
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@
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_infer::infer::type_variable::TypeVariableOriginKind;
11+
use rustc_infer::infer::InferCtxt;
12+
use rustc_middle::ty::{self, AliasKind, Ty, TyCtxt};
13+
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
814
use rustc_span::def_id::LocalDefId;
9-
use rustc_span::Span;
15+
use rustc_span::{Span, Symbol};
1016
use rustc_trait_selection::traits::{self, IsFirstInputType};
1117

1218
#[instrument(skip(tcx), level = "debug")]
@@ -23,20 +29,17 @@ pub(crate) fn orphan_check_impl(
2329
Ok(()) => {}
2430
Err(err) => {
2531
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);
32+
let impl_ = item.expect_impl();
33+
let hir_trait_ref = impl_.of_trait.as_ref().unwrap();
3134

3235
emit_orphan_check_error(
3336
tcx,
34-
sp,
37+
tcx.def_span(impl_def_id),
3538
item.span,
36-
tr.path.span,
39+
hir_trait_ref.path.span,
3740
trait_ref,
3841
impl_.self_ty.span,
39-
impl_.generics,
42+
tcx.generics_of(impl_def_id),
4043
err,
4144
)?
4245
}
@@ -277,7 +280,7 @@ fn emit_orphan_check_error<'tcx>(
277280
trait_span: Span,
278281
trait_ref: ty::TraitRef<'tcx>,
279282
self_ty_span: Span,
280-
generics: &hir::Generics<'tcx>,
283+
generics: &'tcx ty::Generics,
281284
err: traits::OrphanCheckErr<'tcx>,
282285
) -> Result<!, ErrorGuaranteed> {
283286
let self_ty = trait_ref.self_ty();
@@ -404,23 +407,74 @@ fn emit_orphan_check_error<'tcx>(
404407
};
405408
tcx.dcx().emit_err(err_struct)
406409
}
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;
410+
// FIXME(fmease): The uncovered ty may contain infer vars.
411+
// Somwhere we need to remap them to ty params.
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+
};
419+
uncovered_ty.visit_with(&mut collector);
420+
421+
let mut reported = None;
422+
for (param, span) in collector.uncovered_params {
423+
reported.get_or_insert(match local_type {
424+
Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
425+
span,
426+
note: (),
427+
param,
428+
local_type,
429+
}),
430+
None => tcx.dcx().emit_err(errors::TyParamSome { span, note: (), param }),
431+
});
432+
}
433+
434+
struct UncoveredTyParamCollector<'tcx> {
435+
tcx: TyCtxt<'tcx>,
436+
infcx: Option<Box<InferCtxt<'tcx>>>,
437+
generics: &'tcx ty::Generics,
438+
uncovered_params: FxIndexMap<Symbol, Span>,
439+
}
440+
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);
412446
}
413447
}
414448

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 }),
449+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'tcx> {
450+
type BreakTy = !;
451+
452+
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
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+
_ => {}
471+
}
472+
473+
ty.super_visit_with(self)
474+
}
423475
}
476+
477+
reported.unwrap_or_else(|| bug!("failed to find ty param in `{uncovered_ty}`"))
424478
}
425479
})
426480
}

compiler/rustc_hir_analysis/src/errors.rs

+3-3
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

+1
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)]

0 commit comments

Comments
 (0)