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
.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_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 rustc_errors::ErrorGuaranteed;
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::Span;
use rustc_trait_selection::traits::{self, IsFirstInputType};
@ -283,9 +283,14 @@ fn emit_orphan_check_error<'tcx>(
let self_ty = trait_ref.self_ty();
Err(match err {
traits::OrphanCheckErr::NonLocalInputType(tys) => {
let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) =
(Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
let mut sugg = None;
let mut diag = tcx.dcx().create_err(match self_ty.kind() {
ty::Adt(..) => errors::OnlyCurrentTraits::Outside { span: sp, note: () },
_ 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 {
let span = if matches!(is_target_ty, IsFirstInputType::Yes) {
// 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 = 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 =
!trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
match *ty.kind() {
ty::Slice(_) => {
push_to_foreign_or_name(
is_foreign,
&mut foreign,
&mut name,
span,
"slices",
);
if is_foreign {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsForeign { span },
);
} else {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsName { span, name: "slices" },
);
}
}
ty::Array(..) => {
push_to_foreign_or_name(
is_foreign,
&mut foreign,
&mut name,
span,
"arrays",
);
if is_foreign {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsForeign { span },
);
} else {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsName { span, name: "arrays" },
);
}
}
ty::Tuple(..) => {
push_to_foreign_or_name(
is_foreign,
&mut foreign,
&mut name,
span,
"tuples",
);
if is_foreign {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsForeign { span },
);
} else {
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsName { span, name: "tuples" },
);
}
}
ty::Alias(ty::Opaque, ..) => {
opaque.push(errors::OnlyCurrentTraitsOpaque { span })
diag.subdiagnostic(tcx.dcx(), errors::OnlyCurrentTraitsOpaque { span });
}
ty::RawPtr(ptr_ty, mutbl) => {
if !self_ty.has_param() {
let mut_key = mutbl.prefix_str();
sugg = Some(errors::OnlyCurrentTraitsPointerSugg {
wrapper_span: self_ty_span,
struct_span: full_impl_span.shrink_to_lo(),
mut_key,
ptr_ty,
});
diag.subdiagnostic(
tcx.dcx(),
errors::OnlyCurrentTraitsPointerSugg {
wrapper_span: self_ty_span,
struct_span: full_impl_span.shrink_to_lo(),
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() {
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)
diag.emit()
}
traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
let mut sp = sp;

View File

@ -1376,7 +1376,7 @@ pub struct TyParamSome<'a> {
}
#[derive(Diagnostic)]
pub enum OnlyCurrentTraits<'a> {
pub enum OnlyCurrentTraits {
#[diag(hir_analysis_only_current_traits_outside, code = E0117)]
Outside {
#[primary_span]
@ -1384,18 +1384,6 @@ pub enum OnlyCurrentTraits<'a> {
span: Span,
#[note(hir_analysis_only_current_traits_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)]
Primitive {
@ -1404,18 +1392,6 @@ pub enum OnlyCurrentTraits<'a> {
span: Span,
#[note(hir_analysis_only_current_traits_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)]
Arbitrary {
@ -1424,18 +1400,6 @@ pub enum OnlyCurrentTraits<'a> {
span: Span,
#[note(hir_analysis_only_current_traits_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]
pub span: Span,
}
#[derive(Subdiagnostic)]
#[label(hir_analysis_only_current_traits_foreign)]
pub struct OnlyCurrentTraitsForeign {
@ -1477,6 +1440,14 @@ pub struct OnlyCurrentTraitsTy<'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)]
#[multipart_suggestion(
hir_analysis_only_current_traits_pointer_sugg,

View File

@ -1624,6 +1624,13 @@ pub fn new_imm_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
#[inline]
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))
}