Auto merge of #123214 - compiler-errors:subst, r=estebank

Assert that ADTs have the right number of args

We're doing it for many other types, let's also do ADTs 😇
This commit is contained in:
bors 2024-03-30 11:48:31 +00:00
commit 40116ad1ed
4 changed files with 87 additions and 129 deletions

View File

@ -295,6 +295,8 @@ hir_analysis_not_supported_delegation =
{$descr} is not supported yet {$descr} is not supported yet
.label = callee defined here .label = callee defined here
hir_analysis_only_current_traits_adt = `{$name}` is not defined in the current crate
hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait

View File

@ -4,7 +4,7 @@
use crate::errors; use crate::errors;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::ty::{self, AliasKind, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, AliasKind, TyCtxt, TypeVisitableExt};
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::traits::{self, IsFirstInputType}; use rustc_trait_selection::traits::{self, IsFirstInputType};
@ -283,9 +283,14 @@ fn emit_orphan_check_error<'tcx>(
let self_ty = trait_ref.self_ty(); let self_ty = trait_ref.self_ty();
Err(match err { Err(match err {
traits::OrphanCheckErr::NonLocalInputType(tys) => { traits::OrphanCheckErr::NonLocalInputType(tys) => {
let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) = let mut diag = tcx.dcx().create_err(match self_ty.kind() {
(Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()); ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span: sp, note: () },
let mut sugg = None; _ if self_ty.is_primitive() => {
errors::OnlyCurrentTraits::Primitive { span: sp, note: () }
}
_ => errors::OnlyCurrentTraits::Arbitrary { span: sp, note: () },
});
for &(mut ty, is_target_ty) in &tys { for &(mut ty, is_target_ty) in &tys {
let span = if matches!(is_target_ty, IsFirstInputType::Yes) { let span = if matches!(is_target_ty, IsFirstInputType::Yes) {
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>` // Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
@ -296,113 +301,86 @@ fn emit_orphan_check_error<'tcx>(
}; };
ty = tcx.erase_regions(ty); ty = tcx.erase_regions(ty);
ty = match ty.kind() {
// Remove the type arguments from the output, as they are not relevant.
// You can think of this as the reverse of `resolve_vars_if_possible`.
// That way if we had `Vec<MyType>`, we will properly attribute the
// problem to `Vec<T>` and avoid confusing the user if they were to see
// `MyType` in the error.
ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()),
_ => ty,
};
fn push_to_foreign_or_name<'tcx>(
is_foreign: bool,
foreign: &mut Vec<errors::OnlyCurrentTraitsForeign>,
name: &mut Vec<errors::OnlyCurrentTraitsName<'tcx>>,
span: Span,
sname: &'tcx str,
) {
if is_foreign {
foreign.push(errors::OnlyCurrentTraitsForeign { span })
} else {
name.push(errors::OnlyCurrentTraitsName { span, name: sname });
}
}
let is_foreign = let is_foreign =
!trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No); !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
match *ty.kind() { match *ty.kind() {
ty::Slice(_) => { ty::Slice(_) => {
push_to_foreign_or_name( if is_foreign {
is_foreign, diag.subdiagnostic(
&mut foreign, tcx.dcx(),
&mut name, errors::OnlyCurrentTraitsForeign { span },
span, );
"slices", } else {
); diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsName { span, name: "slices" },
);
}
} }
ty::Array(..) => { ty::Array(..) => {
push_to_foreign_or_name( if is_foreign {
is_foreign, diag.subdiagnostic(
&mut foreign, tcx.dcx(),
&mut name, errors::OnlyCurrentTraitsForeign { span },
span, );
"arrays", } else {
); diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsName { span, name: "arrays" },
);
}
} }
ty::Tuple(..) => { ty::Tuple(..) => {
push_to_foreign_or_name( if is_foreign {
is_foreign, diag.subdiagnostic(
&mut foreign, tcx.dcx(),
&mut name, errors::OnlyCurrentTraitsForeign { span },
span, );
"tuples", } else {
); diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsName { span, name: "tuples" },
);
}
} }
ty::Alias(ty::Opaque, ..) => { ty::Alias(ty::Opaque, ..) => {
opaque.push(errors::OnlyCurrentTraitsOpaque { span }) diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span });
} }
ty::RawPtr(ptr_ty, mutbl) => { ty::RawPtr(ptr_ty, mutbl) => {
if !self_ty.has_param() { if !self_ty.has_param() {
let mut_key = mutbl.prefix_str(); diag.subdiagnostic(
sugg = Some(errors::OnlyCurrentTraitsPointerSugg { tcx.dcx(),
wrapper_span: self_ty_span, errors::OnlyCurrentTraitsPointerSugg {
struct_span: full_impl_span.shrink_to_lo(), wrapper_span: self_ty_span,
mut_key, struct_span: full_impl_span.shrink_to_lo(),
ptr_ty, mut_key: mutbl.prefix_str(),
}); ptr_ty,
},
);
} }
pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty }); diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsPointer { span, pointer: ty },
);
}
ty::Adt(adt_def, _) => {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsAdt {
span,
name: tcx.def_path_str(adt_def.did()),
},
);
}
_ => {
diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsTy { span, ty });
} }
_ => ty_diag.push(errors::OnlyCurrentTraitsTy { span, ty }),
} }
} }
let err_struct = match self_ty.kind() { diag.emit()
ty::Adt(..) => errors::OnlyCurrentTraits::Outside {
span: sp,
note: (),
opaque,
foreign,
name,
pointer,
ty: ty_diag,
sugg,
},
_ if self_ty.is_primitive() => errors::OnlyCurrentTraits::Primitive {
span: sp,
note: (),
opaque,
foreign,
name,
pointer,
ty: ty_diag,
sugg,
},
_ => errors::OnlyCurrentTraits::Arbitrary {
span: sp,
note: (),
opaque,
foreign,
name,
pointer,
ty: ty_diag,
sugg,
},
};
tcx.dcx().emit_err(err_struct)
} }
traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => { traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
let mut sp = sp; let mut sp = sp;

View File

@ -1376,7 +1376,7 @@ pub struct TyParamSome<'a> {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
pub enum OnlyCurrentTraits<'a> { pub enum OnlyCurrentTraits {
#[diag(hir_analysis_only_current_traits_outside, code = E0117)] #[diag(hir_analysis_only_current_traits_outside, code = E0117)]
Outside { Outside {
#[primary_span] #[primary_span]
@ -1384,18 +1384,6 @@ pub enum OnlyCurrentTraits<'a> {
span: Span, span: Span,
#[note(hir_analysis_only_current_traits_note)] #[note(hir_analysis_only_current_traits_note)]
note: (), note: (),
#[subdiagnostic]
opaque: Vec<OnlyCurrentTraitsOpaque>,
#[subdiagnostic]
foreign: Vec<OnlyCurrentTraitsForeign>,
#[subdiagnostic]
name: Vec<OnlyCurrentTraitsName<'a>>,
#[subdiagnostic]
pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
#[subdiagnostic]
ty: Vec<OnlyCurrentTraitsTy<'a>>,
#[subdiagnostic]
sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
}, },
#[diag(hir_analysis_only_current_traits_primitive, code = E0117)] #[diag(hir_analysis_only_current_traits_primitive, code = E0117)]
Primitive { Primitive {
@ -1404,18 +1392,6 @@ pub enum OnlyCurrentTraits<'a> {
span: Span, span: Span,
#[note(hir_analysis_only_current_traits_note)] #[note(hir_analysis_only_current_traits_note)]
note: (), note: (),
#[subdiagnostic]
opaque: Vec<OnlyCurrentTraitsOpaque>,
#[subdiagnostic]
foreign: Vec<OnlyCurrentTraitsForeign>,
#[subdiagnostic]
name: Vec<OnlyCurrentTraitsName<'a>>,
#[subdiagnostic]
pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
#[subdiagnostic]
ty: Vec<OnlyCurrentTraitsTy<'a>>,
#[subdiagnostic]
sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
}, },
#[diag(hir_analysis_only_current_traits_arbitrary, code = E0117)] #[diag(hir_analysis_only_current_traits_arbitrary, code = E0117)]
Arbitrary { Arbitrary {
@ -1424,18 +1400,6 @@ pub enum OnlyCurrentTraits<'a> {
span: Span, span: Span,
#[note(hir_analysis_only_current_traits_note)] #[note(hir_analysis_only_current_traits_note)]
note: (), note: (),
#[subdiagnostic]
opaque: Vec<OnlyCurrentTraitsOpaque>,
#[subdiagnostic]
foreign: Vec<OnlyCurrentTraitsForeign>,
#[subdiagnostic]
name: Vec<OnlyCurrentTraitsName<'a>>,
#[subdiagnostic]
pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
#[subdiagnostic]
ty: Vec<OnlyCurrentTraitsTy<'a>>,
#[subdiagnostic]
sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
}, },
} }
@ -1445,7 +1409,6 @@ pub struct OnlyCurrentTraitsOpaque {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[label(hir_analysis_only_current_traits_foreign)] #[label(hir_analysis_only_current_traits_foreign)]
pub struct OnlyCurrentTraitsForeign { pub struct OnlyCurrentTraitsForeign {
@ -1477,6 +1440,14 @@ pub struct OnlyCurrentTraitsTy<'a> {
pub ty: Ty<'a>, pub ty: Ty<'a>,
} }
#[derive(Subdiagnostic)]
#[label(hir_analysis_only_current_traits_adt)]
pub struct OnlyCurrentTraitsAdt {
#[primary_span]
pub span: Span,
pub name: String,
}
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[multipart_suggestion( #[multipart_suggestion(
hir_analysis_only_current_traits_pointer_sugg, hir_analysis_only_current_traits_pointer_sugg,

View File

@ -1624,6 +1624,13 @@ impl<'tcx> Ty<'tcx> {
#[inline] #[inline]
pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
debug_assert_eq!(
tcx.generics_of(def.did()).count(),
args.len(),
"wrong number of args for ADT: {:#?} vs {:#?}",
tcx.generics_of(def.did()).params,
args
);
Ty::new(tcx, Adt(def, args)) Ty::new(tcx, Adt(def, args))
} }