Skip to content

Commit d47b6f5

Browse files
committed
Auto merge of #123240 - compiler-errors:assert-args-compat, r=<try>
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 dd5e502 + e50622c commit d47b6f5

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
@@ -7,9 +7,10 @@ use rustc_hir as hir;
77
use rustc_hir::def::{DefKind, Res};
88
use rustc_hir::def_id::DefId;
99
use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
10-
use rustc_middle::ty::{self, Ty};
10+
use rustc_middle::ty::fold::BottomUpFolder;
11+
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
1112
use rustc_middle::ty::{DynKind, ToPredicate};
12-
use rustc_span::Span;
13+
use rustc_span::{ErrorGuaranteed, Span};
1314
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
1415
use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
1516

@@ -267,12 +268,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
267268
if arg == dummy_self.into() {
268269
let param = &generics.params[index];
269270
missing_type_params.push(param.name);
270-
return Ty::new_misc_error(tcx).into();
271+
Ty::new_misc_error(tcx).into()
271272
} else if arg.walk().any(|arg| arg == dummy_self.into()) {
272273
references_self = true;
273-
return Ty::new_misc_error(tcx).into();
274+
let guar = tcx.dcx().span_delayed_bug(
275+
span,
276+
"trait object trait bounds reference `Self`",
277+
);
278+
replace_dummy_self_with_error(tcx, arg, guar)
279+
} else {
280+
arg
274281
}
275-
arg
276282
})
277283
.collect();
278284
let args = tcx.mk_args(&args);
@@ -327,18 +333,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
327333
let guar = tcx
328334
.dcx()
329335
.span_delayed_bug(span, "trait object projection bounds reference `Self`");
330-
let args: Vec<_> = b
331-
.projection_ty
332-
.args
333-
.iter()
334-
.map(|arg| {
335-
if arg.walk().any(|arg| arg == dummy_self.into()) {
336-
return Ty::new_error(tcx, guar).into();
337-
}
338-
arg
339-
})
340-
.collect();
341-
b.projection_ty.args = tcx.mk_args(&args);
336+
b.projection_ty = replace_dummy_self_with_error(tcx, b.projection_ty, guar);
342337
}
343338

344339
ty::ExistentialProjection::erase_self_ty(tcx, b)
@@ -396,3 +391,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
396391
Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
397392
}
398393
}
394+
395+
fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
396+
tcx: TyCtxt<'tcx>,
397+
t: T,
398+
guar: ErrorGuaranteed,
399+
) -> T {
400+
t.fold_with(&mut BottomUpFolder {
401+
tcx,
402+
ty_op: |ty| {
403+
if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty }
404+
},
405+
lt_op: |lt| lt,
406+
ct_op: |ct| ct,
407+
})
408+
}

compiler/rustc_middle/src/ty/context.rs

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

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

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

19862057
#[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

@@ -1711,11 +1705,7 @@ impl<'tcx> Ty<'tcx> {
17111705
def_id: DefId,
17121706
closure_args: GenericArgsRef<'tcx>,
17131707
) -> Ty<'tcx> {
1714-
debug_assert_eq!(
1715-
closure_args.len(),
1716-
tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3,
1717-
"closure constructed with incorrect generic parameters"
1718-
);
1708+
tcx.debug_assert_args_compatible(def_id, closure_args);
17191709
Ty::new(tcx, Closure(def_id, closure_args))
17201710
}
17211711

@@ -1725,11 +1715,7 @@ impl<'tcx> Ty<'tcx> {
17251715
def_id: DefId,
17261716
closure_args: GenericArgsRef<'tcx>,
17271717
) -> Ty<'tcx> {
1728-
debug_assert_eq!(
1729-
closure_args.len(),
1730-
tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5,
1731-
"closure constructed with incorrect generic parameters"
1732-
);
1718+
tcx.debug_assert_args_compatible(def_id, closure_args);
17331719
Ty::new(tcx, CoroutineClosure(def_id, closure_args))
17341720
}
17351721

@@ -1739,11 +1725,7 @@ impl<'tcx> Ty<'tcx> {
17391725
def_id: DefId,
17401726
coroutine_args: GenericArgsRef<'tcx>,
17411727
) -> Ty<'tcx> {
1742-
debug_assert_eq!(
1743-
coroutine_args.len(),
1744-
tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6,
1745-
"coroutine constructed with incorrect number of generic parameters"
1746-
);
1728+
tcx.debug_assert_args_compatible(def_id, coroutine_args);
17471729
Ty::new(tcx, Coroutine(def_id, coroutine_args))
17481730
}
17491731

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};
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)