diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index b5b3a9131c57f..5adf95c7a1456 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -7,9 +7,10 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::fold::BottomUpFolder; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{DynKind, ToPredicate}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits::error_reporting::report_object_safety_error; use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations}; @@ -267,12 +268,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if arg == dummy_self.into() { let param = &generics.params[index]; missing_type_params.push(param.name); - return Ty::new_misc_error(tcx).into(); + Ty::new_misc_error(tcx).into() } else if arg.walk().any(|arg| arg == dummy_self.into()) { references_self = true; - return Ty::new_misc_error(tcx).into(); + let guar = tcx.dcx().span_delayed_bug( + span, + "trait object trait bounds reference `Self`", + ); + replace_dummy_self_with_error(tcx, arg, guar) + } else { + arg } - arg }) .collect(); let args = tcx.mk_args(&args); @@ -327,18 +333,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let guar = tcx .dcx() .span_delayed_bug(span, "trait object projection bounds reference `Self`"); - let args: Vec<_> = b - .projection_ty - .args - .iter() - .map(|arg| { - if arg.walk().any(|arg| arg == dummy_self.into()) { - return Ty::new_error(tcx, guar).into(); - } - arg - }) - .collect(); - b.projection_ty.args = tcx.mk_args(&args); + b.projection_ty = replace_dummy_self_with_error(tcx, b.projection_ty, guar); } ty::ExistentialProjection::erase_self_ty(tcx, b) @@ -396,3 +391,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_dynamic(tcx, existential_predicates, region_bound, representation) } } + +fn replace_dummy_self_with_error<'tcx, T: TypeFoldable>>( + tcx: TyCtxt<'tcx>, + t: T, + guar: ErrorGuaranteed, +) -> T { + t.fold_with(&mut BottomUpFolder { + tcx, + ty_op: |ty| { + if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty } + }, + lt_op: |lt| lt, + ct_op: |ct| ct, + }) +} diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 3713883eb00d7..60e675bca94f6 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -135,6 +135,7 @@ impl<'tcx> Const<'tcx> { uv: ty::UnevaluatedConst<'tcx>, ty: Ty<'tcx>, ) -> Const<'tcx> { + tcx.debug_assert_args_compatible(uv.def, uv.args); Const::new(tcx, ty::ConstKind::Unevaluated(uv), ty) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 188cb50849dc1..c14a346a8940f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1954,33 +1954,106 @@ impl<'tcx> TyCtxt<'tcx> { if pred.kind() != binder { self.mk_predicate(binder) } else { pred } } - #[inline(always)] - pub(crate) fn check_and_mk_args( + pub fn check_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) -> bool { + self.check_args_compatible_inner(def_id, args, false) + } + + fn check_args_compatible_inner( self, - _def_id: DefId, - args: impl IntoIterator>>, - ) -> GenericArgsRef<'tcx> { - let args = args.into_iter().map(Into::into); - #[cfg(debug_assertions)] + def_id: DefId, + args: &'tcx [ty::GenericArg<'tcx>], + nested: bool, + ) -> bool { + let generics = self.generics_of(def_id); + + // IATs themselves have a weird arg setup (self + own args), but nested items *in* IATs + // (namely: opaques, i.e. ATPITs) do not. + let own_args = if !nested + && let DefKind::AssocTy = self.def_kind(def_id) + && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) { - let generics = self.generics_of(_def_id); + if generics.params.len() + 1 != args.len() { + return false; + } + + if !matches!(args[0].unpack(), ty::GenericArgKind::Type(_)) { + return false; + } + + &args[1..] + } else { + if generics.count() != args.len() { + return false; + } + + let (parent_args, own_args) = args.split_at(generics.parent_count); - let n = if let DefKind::AssocTy = self.def_kind(_def_id) - && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(_def_id)) + if let Some(parent) = generics.parent + && !self.check_args_compatible_inner(parent, parent_args, true) { - // If this is an inherent projection. - generics.params.len() + 1 - } else { - generics.count() - }; - assert_eq!( - (n, Some(n)), - args.size_hint(), - "wrong number of generic parameters for {_def_id:?}: {:?}", - args.collect::>(), - ); + return false; + } + + own_args + }; + + for (param, arg) in std::iter::zip(&generics.params, own_args) { + match (¶m.kind, arg.unpack()) { + (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) + | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) + | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {} + _ => return false, + } } - self.mk_args_from_iter(args) + + true + } + + /// With `cfg(debug_assertions)`, assert that args are compatible with their generics, + /// and print out the args if not. + #[cfg_attr(not(debug_assertions), allow(unused_variables))] + pub fn debug_assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) { + #[cfg(debug_assertions)] + { + if !self.check_args_compatible(def_id, args) { + if let DefKind::AssocTy = self.def_kind(def_id) + && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) + { + bug!( + "args not compatible with generics for {}: args={:#?}, generics={:#?}", + self.def_path_str(def_id), + args, + // Make `[Self, GAT_ARGS...]` (this could be simplified) + self.mk_args_from_iter( + [self.types.self_param.into()].into_iter().chain( + self.generics_of(def_id) + .own_args(ty::GenericArgs::identity_for_item(self, def_id)) + .iter() + .copied() + ) + ) + ); + } else { + bug!( + "args not compatible with generics for {}: args={:#?}, generics={:#?}", + self.def_path_str(def_id), + args, + ty::GenericArgs::identity_for_item(self, def_id) + ); + } + } + } + } + + #[inline(always)] + pub(crate) fn check_and_mk_args( + self, + def_id: DefId, + args: impl IntoIterator>>, + ) -> GenericArgsRef<'tcx> { + let args = self.mk_args_from_iter(args.into_iter().map(Into::into)); + self.debug_assert_args_compatible(def_id, args); + args } #[inline] diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index b5e619f1e2a3c..30997d1350d9d 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1624,13 +1624,7 @@ impl<'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 - ); + tcx.debug_assert_args_compatible(def.did(), args); Ty::new(tcx, Adt(def, args)) } @@ -1711,11 +1705,7 @@ impl<'tcx> Ty<'tcx> { def_id: DefId, closure_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - debug_assert_eq!( - closure_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3, - "closure constructed with incorrect generic parameters" - ); + tcx.debug_assert_args_compatible(def_id, closure_args); Ty::new(tcx, Closure(def_id, closure_args)) } @@ -1725,11 +1715,7 @@ impl<'tcx> Ty<'tcx> { def_id: DefId, closure_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - debug_assert_eq!( - closure_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5, - "closure constructed with incorrect generic parameters" - ); + tcx.debug_assert_args_compatible(def_id, closure_args); Ty::new(tcx, CoroutineClosure(def_id, closure_args)) } @@ -1739,11 +1725,7 @@ impl<'tcx> Ty<'tcx> { def_id: DefId, coroutine_args: GenericArgsRef<'tcx>, ) -> Ty<'tcx> { - debug_assert_eq!( - coroutine_args.len(), - tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6, - "coroutine constructed with incorrect number of generic parameters" - ); + tcx.debug_assert_args_compatible(def_id, coroutine_args); Ty::new(tcx, Coroutine(def_id, coroutine_args)) } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 6668889323512..d8aeadd07b3d9 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -1,4 +1,4 @@ -use crate::traits::{check_args_compatible, specialization_graph}; +use crate::traits::specialization_graph; use super::assembly::structural_traits::AsyncCallableRelevantTypes; use super::assembly::{self, structural_traits, Candidate}; @@ -247,7 +247,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { assoc_def.defining_node, ); - if !check_args_compatible(tcx, assoc_def.item, args) { + if !tcx.check_args_compatible(assoc_def.item.def_id, args) { return error_response( ecx, "associated item has mismatched generic item arguments", diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c875d3da47e5f..e1b2e5b6c224a 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -61,12 +61,12 @@ pub use self::specialize::{ pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::elaborate; -pub use self::util::{ - check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds, - transitive_bounds_that_define_assoc_item, SupertraitDefIds, -}; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; +pub use self::util::{ + supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item, + SupertraitDefIds, +}; pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; pub use rustc_infer::traits::*; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index c33e24b1094d4..9d744d9a03214 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2,7 +2,6 @@ use std::ops::ControlFlow; -use super::check_args_compatible; use super::specialization_graph; use super::translate_args; use super::util; @@ -2030,7 +2029,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( } else { ty.map_bound(|ty| ty.into()) }; - if !check_args_compatible(tcx, assoc_ty.item, args) { + if !tcx.check_args_compatible(assoc_ty.item.def_id, args) { let err = Ty::new_error_with_message( tcx, obligation.cause.span, diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 466a53d8ce029..d29fc7921bcbd 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -344,48 +344,6 @@ pub enum TupleArgumentsFlag { No, } -// Verify that the trait item and its implementation have compatible args lists -pub fn check_args_compatible<'tcx>( - tcx: TyCtxt<'tcx>, - assoc_item: ty::AssocItem, - args: ty::GenericArgsRef<'tcx>, -) -> bool { - fn check_args_compatible_inner<'tcx>( - tcx: TyCtxt<'tcx>, - generics: &'tcx ty::Generics, - args: &'tcx [ty::GenericArg<'tcx>], - ) -> bool { - if generics.count() != args.len() { - return false; - } - - let (parent_args, own_args) = args.split_at(generics.parent_count); - - if let Some(parent) = generics.parent - && let parent_generics = tcx.generics_of(parent) - && !check_args_compatible_inner(tcx, parent_generics, parent_args) - { - return false; - } - - for (param, arg) in std::iter::zip(&generics.params, own_args) { - match (¶m.kind, arg.unpack()) { - (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) - | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) - | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {} - _ => return false, - } - } - - true - } - - let generics = tcx.generics_of(assoc_item.def_id); - // Chop off any additional args (RPITIT) args - let args = &args[0..generics.count().min(args.len())]; - check_args_compatible_inner(tcx, generics, args) -} - /// Executes `f` on `value` after replacing all escaping bound variables with placeholders /// and then replaces these placeholders with the original bound variables in the result. /// diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index fc16edc6d1309..a652bb781161c 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -7,7 +7,6 @@ use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_span::Span; -use rustc_trait_selection::traits::check_args_compatible; use crate::errors::{DuplicateArg, NotParam}; @@ -250,7 +249,7 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { ty::GenericArgs::identity_for_item(self.tcx, parent), ); - if check_args_compatible(self.tcx, assoc, impl_args) { + if self.tcx.check_args_compatible(assoc.def_id, impl_args) { self.tcx .type_of(assoc.def_id) .instantiate(self.tcx, impl_args) diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs index ab21dae7dc50d..7a51037324f28 100644 --- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs +++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs @@ -14,6 +14,7 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I { //~^ ERROR binding for associated type `Item` references lifetime `'missing` //~| ERROR binding for associated type `Item` references lifetime `'missing` //~| ERROR `()` is not an iterator + //~| WARNING impl trait in impl method signature does not match trait method signature } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr index d8a2eef94a180..67c4df0f3a9eb 100644 --- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr +++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr @@ -32,7 +32,24 @@ LL | fn iter(&self) -> impl for<'missing> Iterator $DIR/span-bug-issue-121457.rs:13:51 + | +LL | fn iter(&self) -> impl Iterator; + | ------------- return type from trait method defined here +... +LL | fn iter(&self) -> impl for<'missing> Iterator> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this bound is stronger than that defined on the trait + | + = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate + = note: we are soliciting feedback, see issue #121718 for more information + = note: `#[warn(refining_impl_trait_reachable)]` on by default +help: replace the return type so that it matches the trait + | +LL | fn iter(&self) -> impl Iterator {} + | ~~~~~~~~~~~~~ + +error: aborting due to 4 previous errors; 1 warning emitted Some errors have detailed explanations: E0195, E0277, E0582. For more information about an error, try `rustc --explain E0195`. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy