Skip to content

Commit 94991b9

Browse files
committed
Auto merge of rust-lang#123240 - compiler-errors:assert-args-compat, r=fmease
Assert that args are actually compatible with their generics, rather than just their count Right now we just check that the number of args is right, rather than actually checking the kinds. Uplift a helper fn that I wrote from trait selection to do just that. Found a couple bugs along the way. r? `@lcnr` or `@fmease` (or anyone really lol)
2 parents 4fd4797 + bd8ca78 commit 94991b9

File tree

10 files changed

+151
-114
lines changed

10 files changed

+151
-114
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs

+27-17
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ use rustc_hir as hir;
66
use rustc_hir::def::{DefKind, Res};
77
use rustc_hir::def_id::DefId;
88
use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
9-
use rustc_middle::ty::{self, Ty};
9+
use rustc_middle::ty::fold::BottomUpFolder;
10+
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
1011
use rustc_middle::ty::{DynKind, ToPredicate};
11-
use rustc_span::Span;
12+
use rustc_span::{ErrorGuaranteed, Span};
1213
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
1314
use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
1415

@@ -228,12 +229,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
228229
if arg == dummy_self.into() {
229230
let param = &generics.params[index];
230231
missing_type_params.push(param.name);
231-
return Ty::new_misc_error(tcx).into();
232+
Ty::new_misc_error(tcx).into()
232233
} else if arg.walk().any(|arg| arg == dummy_self.into()) {
233234
references_self = true;
234-
return Ty::new_misc_error(tcx).into();
235+
let guar = tcx.dcx().span_delayed_bug(
236+
span,
237+
"trait object trait bounds reference `Self`",
238+
);
239+
replace_dummy_self_with_error(tcx, arg, guar)
240+
} else {
241+
arg
235242
}
236-
arg
237243
})
238244
.collect();
239245
let args = tcx.mk_args(&args);
@@ -288,18 +294,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
288294
let guar = tcx
289295
.dcx()
290296
.span_delayed_bug(span, "trait object projection bounds reference `Self`");
291-
let args: Vec<_> = b
292-
.projection_ty
293-
.args
294-
.iter()
295-
.map(|arg| {
296-
if arg.walk().any(|arg| arg == dummy_self.into()) {
297-
return Ty::new_error(tcx, guar).into();
298-
}
299-
arg
300-
})
301-
.collect();
302-
b.projection_ty.args = tcx.mk_args(&args);
297+
b.projection_ty = replace_dummy_self_with_error(tcx, b.projection_ty, guar);
303298
}
304299

305300
ty::ExistentialProjection::erase_self_ty(tcx, b)
@@ -357,3 +352,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
357352
Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
358353
}
359354
}
355+
356+
fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
357+
tcx: TyCtxt<'tcx>,
358+
t: T,
359+
guar: ErrorGuaranteed,
360+
) -> T {
361+
t.fold_with(&mut BottomUpFolder {
362+
tcx,
363+
ty_op: |ty| {
364+
if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty }
365+
},
366+
lt_op: |lt| lt,
367+
ct_op: |ct| ct,
368+
})
369+
}

compiler/rustc_middle/src/ty/context.rs

+93-22
Original file line numberDiff line numberDiff line change
@@ -1961,33 +1961,104 @@ impl<'tcx> TyCtxt<'tcx> {
19611961
if pred.kind() != binder { self.mk_predicate(binder) } else { pred }
19621962
}
19631963

1964-
#[inline(always)]
1965-
pub(crate) fn check_and_mk_args(
1964+
pub fn check_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) -> bool {
1965+
self.check_args_compatible_inner(def_id, args, false)
1966+
}
1967+
1968+
fn check_args_compatible_inner(
19661969
self,
1967-
_def_id: DefId,
1968-
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
1969-
) -> GenericArgsRef<'tcx> {
1970-
let args = args.into_iter().map(Into::into);
1971-
#[cfg(debug_assertions)]
1970+
def_id: DefId,
1971+
args: &'tcx [ty::GenericArg<'tcx>],
1972+
nested: bool,
1973+
) -> bool {
1974+
let generics = self.generics_of(def_id);
1975+
1976+
// IATs themselves have a weird arg setup (self + own args), but nested items *in* IATs
1977+
// (namely: opaques, i.e. ATPITs) do not.
1978+
let own_args = if !nested
1979+
&& let DefKind::AssocTy = self.def_kind(def_id)
1980+
&& let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id))
19721981
{
1973-
let generics = self.generics_of(_def_id);
1982+
if generics.params.len() + 1 != args.len() {
1983+
return false;
1984+
}
19741985

1975-
let n = if let DefKind::AssocTy = self.def_kind(_def_id)
1976-
&& let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(_def_id))
1986+
if !matches!(args[0].unpack(), ty::GenericArgKind::Type(_)) {
1987+
return false;
1988+
}
1989+
1990+
&args[1..]
1991+
} else {
1992+
if generics.count() != args.len() {
1993+
return false;
1994+
}
1995+
1996+
let (parent_args, own_args) = args.split_at(generics.parent_count);
1997+
1998+
if let Some(parent) = generics.parent
1999+
&& !self.check_args_compatible_inner(parent, parent_args, true)
19772000
{
1978-
// If this is an inherent projection.
1979-
generics.params.len() + 1
1980-
} else {
1981-
generics.count()
1982-
};
1983-
assert_eq!(
1984-
(n, Some(n)),
1985-
args.size_hint(),
1986-
"wrong number of generic parameters for {_def_id:?}: {:?}",
1987-
args.collect::<Vec<_>>(),
1988-
);
2001+
return false;
2002+
}
2003+
2004+
own_args
2005+
};
2006+
2007+
for (param, arg) in std::iter::zip(&generics.params, own_args) {
2008+
match (&param.kind, arg.unpack()) {
2009+
(ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
2010+
| (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
2011+
| (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
2012+
_ => return false,
2013+
}
19892014
}
1990-
self.mk_args_from_iter(args)
2015+
2016+
true
2017+
}
2018+
2019+
/// With `cfg(debug_assertions)`, assert that args are compatible with their generics,
2020+
/// and print out the args if not.
2021+
pub fn debug_assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) {
2022+
if cfg!(debug_assertions) {
2023+
if !self.check_args_compatible(def_id, args) {
2024+
if let DefKind::AssocTy = self.def_kind(def_id)
2025+
&& let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id))
2026+
{
2027+
bug!(
2028+
"args not compatible with generics for {}: args={:#?}, generics={:#?}",
2029+
self.def_path_str(def_id),
2030+
args,
2031+
// Make `[Self, GAT_ARGS...]` (this could be simplified)
2032+
self.mk_args_from_iter(
2033+
[self.types.self_param.into()].into_iter().chain(
2034+
self.generics_of(def_id)
2035+
.own_args(ty::GenericArgs::identity_for_item(self, def_id))
2036+
.iter()
2037+
.copied()
2038+
)
2039+
)
2040+
);
2041+
} else {
2042+
bug!(
2043+
"args not compatible with generics for {}: args={:#?}, generics={:#?}",
2044+
self.def_path_str(def_id),
2045+
args,
2046+
ty::GenericArgs::identity_for_item(self, def_id)
2047+
);
2048+
}
2049+
}
2050+
}
2051+
}
2052+
2053+
#[inline(always)]
2054+
pub(crate) fn check_and_mk_args(
2055+
self,
2056+
def_id: DefId,
2057+
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
2058+
) -> GenericArgsRef<'tcx> {
2059+
let args = self.mk_args_from_iter(args.into_iter().map(Into::into));
2060+
self.debug_assert_args_compatible(def_id, args);
2061+
args
19912062
}
19922063

19932064
#[inline]

compiler/rustc_middle/src/ty/sty.rs

+4-22
Original file line numberDiff line numberDiff line change
@@ -1624,13 +1624,7 @@ impl<'tcx> Ty<'tcx> {
16241624

16251625
#[inline]
16261626
pub fn new_adt(tcx: TyCtxt<'tcx>, def: AdtDef<'tcx>, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
1627-
debug_assert_eq!(
1628-
tcx.generics_of(def.did()).count(),
1629-
args.len(),
1630-
"wrong number of args for ADT: {:#?} vs {:#?}",
1631-
tcx.generics_of(def.did()).params,
1632-
args
1633-
);
1627+
tcx.debug_assert_args_compatible(def.did(), args);
16341628
Ty::new(tcx, Adt(def, args))
16351629
}
16361630

@@ -1715,11 +1709,7 @@ impl<'tcx> Ty<'tcx> {
17151709
def_id: DefId,
17161710
closure_args: GenericArgsRef<'tcx>,
17171711
) -> Ty<'tcx> {
1718-
debug_assert_eq!(
1719-
closure_args.len(),
1720-
tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3,
1721-
"closure constructed with incorrect generic parameters"
1722-
);
1712+
tcx.debug_assert_args_compatible(def_id, closure_args);
17231713
Ty::new(tcx, Closure(def_id, closure_args))
17241714
}
17251715

@@ -1729,11 +1719,7 @@ impl<'tcx> Ty<'tcx> {
17291719
def_id: DefId,
17301720
closure_args: GenericArgsRef<'tcx>,
17311721
) -> Ty<'tcx> {
1732-
debug_assert_eq!(
1733-
closure_args.len(),
1734-
tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5,
1735-
"closure constructed with incorrect generic parameters"
1736-
);
1722+
tcx.debug_assert_args_compatible(def_id, closure_args);
17371723
Ty::new(tcx, CoroutineClosure(def_id, closure_args))
17381724
}
17391725

@@ -1743,11 +1729,7 @@ impl<'tcx> Ty<'tcx> {
17431729
def_id: DefId,
17441730
coroutine_args: GenericArgsRef<'tcx>,
17451731
) -> Ty<'tcx> {
1746-
debug_assert_eq!(
1747-
coroutine_args.len(),
1748-
tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6,
1749-
"coroutine constructed with incorrect number of generic parameters"
1750-
);
1732+
tcx.debug_assert_args_compatible(def_id, coroutine_args);
17511733
Ty::new(tcx, Coroutine(def_id, coroutine_args))
17521734
}
17531735

compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::traits::{check_args_compatible, specialization_graph};
1+
use crate::traits::specialization_graph;
22

33
use super::assembly::structural_traits::AsyncCallableRelevantTypes;
44
use super::assembly::{self, structural_traits, Candidate};
@@ -247,7 +247,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
247247
assoc_def.defining_node,
248248
);
249249

250-
if !check_args_compatible(tcx, assoc_def.item, args) {
250+
if !tcx.check_args_compatible(assoc_def.item.def_id, args) {
251251
return error_response(
252252
ecx,
253253
"associated item has mismatched generic item arguments",

compiler/rustc_trait_selection/src/traits/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ pub use self::specialize::{
6161
pub use self::structural_match::search_for_structural_match_violation;
6262
pub use self::structural_normalize::StructurallyNormalizeExt;
6363
pub use self::util::elaborate;
64-
pub use self::util::{
65-
check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds,
66-
transitive_bounds_that_define_assoc_item, SupertraitDefIds,
67-
};
6864
pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};
6965
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
66+
pub use self::util::{
67+
supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item,
68+
SupertraitDefIds,
69+
};
7070
pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
7171

7272
pub use rustc_infer::traits::*;

compiler/rustc_trait_selection/src/traits/project.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
33
use std::ops::ControlFlow;
44

5-
use super::check_args_compatible;
65
use super::specialization_graph;
76
use super::translate_args;
87
use super::util;
@@ -2030,7 +2029,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
20302029
} else {
20312030
ty.map_bound(|ty| ty.into())
20322031
};
2033-
if !check_args_compatible(tcx, assoc_ty.item, args) {
2032+
if !tcx.check_args_compatible(assoc_ty.item.def_id, args) {
20342033
let err = Ty::new_error_with_message(
20352034
tcx,
20362035
obligation.cause.span,

compiler/rustc_trait_selection/src/traits/util.rs

-42
Original file line numberDiff line numberDiff line change
@@ -344,48 +344,6 @@ pub enum TupleArgumentsFlag {
344344
No,
345345
}
346346

347-
// Verify that the trait item and its implementation have compatible args lists
348-
pub fn check_args_compatible<'tcx>(
349-
tcx: TyCtxt<'tcx>,
350-
assoc_item: ty::AssocItem,
351-
args: ty::GenericArgsRef<'tcx>,
352-
) -> bool {
353-
fn check_args_compatible_inner<'tcx>(
354-
tcx: TyCtxt<'tcx>,
355-
generics: &'tcx ty::Generics,
356-
args: &'tcx [ty::GenericArg<'tcx>],
357-
) -> bool {
358-
if generics.count() != args.len() {
359-
return false;
360-
}
361-
362-
let (parent_args, own_args) = args.split_at(generics.parent_count);
363-
364-
if let Some(parent) = generics.parent
365-
&& let parent_generics = tcx.generics_of(parent)
366-
&& !check_args_compatible_inner(tcx, parent_generics, parent_args)
367-
{
368-
return false;
369-
}
370-
371-
for (param, arg) in std::iter::zip(&generics.params, own_args) {
372-
match (&param.kind, arg.unpack()) {
373-
(ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
374-
| (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
375-
| (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
376-
_ => return false,
377-
}
378-
}
379-
380-
true
381-
}
382-
383-
let generics = tcx.generics_of(assoc_item.def_id);
384-
// Chop off any additional args (RPITIT) args
385-
let args = &args[0..generics.count().min(args.len())];
386-
check_args_compatible_inner(tcx, generics, args)
387-
}
388-
389347
/// Executes `f` on `value` after replacing all escaping bound variables with placeholders
390348
/// and then replaces these placeholders with the original bound variables in the result.
391349
///

compiler/rustc_ty_utils/src/opaque_types.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
77
use rustc_middle::ty::{self, Ty, TyCtxt};
88
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
99
use rustc_span::Span;
10-
use rustc_trait_selection::traits::check_args_compatible;
1110

1211
use crate::errors::{DuplicateArg, NotParam};
1312

@@ -250,7 +249,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
250249
ty::GenericArgs::identity_for_item(self.tcx, parent),
251250
);
252251

253-
if check_args_compatible(self.tcx, assoc, impl_args) {
252+
if self.tcx.check_args_compatible(assoc.def_id, impl_args) {
254253
self.tcx
255254
.type_of(assoc.def_id)
256255
.instantiate(self.tcx, impl_args)

tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I {
1414
//~^ ERROR binding for associated type `Item` references lifetime `'missing`
1515
//~| ERROR binding for associated type `Item` references lifetime `'missing`
1616
//~| ERROR `()` is not an iterator
17+
//~| WARNING impl trait in impl method signature does not match trait method signature
1718
}
1819

1920
fn main() {}

0 commit comments

Comments
 (0)