diff --git a/compiler/rustc_codegen_cranelift/example/issue-59326.rs b/compiler/rustc_codegen_cranelift/example/issue-59326.rs index 70b7c94e15c11..26b3535ecdd93 100644 --- a/compiler/rustc_codegen_cranelift/example/issue-59326.rs +++ b/compiler/rustc_codegen_cranelift/example/issue-59326.rs @@ -1,5 +1,8 @@ // Based on https://github.com/rust-lang/rust/blob/689511047a75a30825e367d4fd45c74604d0b15e/tests/ui/issues/issue-59326.rs#L1 // check-pass + +#![allow(dyn_assoc_redundant, dyn_assoc_shadowed)] + trait Service { type S; } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index e59ff02642cf1..8a9bfb5e262a6 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -1,9 +1,13 @@ -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; +use rustc_hir::HirId; use rustc_hir::def::{DefKind, Res}; -use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; +use rustc_hir::def_id::DefId; +use rustc_lint_defs::builtin::{ + DYN_ASSOC_REDUNDANT, DYN_ASSOC_SHADOWED, UNUSED_ASSOCIATED_TYPE_BOUNDS, +}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::{ self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, @@ -28,7 +32,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub(super) fn lower_trait_object_ty( &self, span: Span, - hir_id: hir::HirId, + hir_id: HirId, hir_bounds: &[hir::PolyTraitRef<'tcx>], lifetime: &hir::Lifetime, representation: DynKind, @@ -59,12 +63,49 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - let (trait_bounds, mut projection_bounds) = + let (trait_bounds, elaborated_projection_bounds) = traits::expand_trait_aliases(tcx, user_written_bounds.clauses()); let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds .into_iter() .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); + // Map the projection bounds onto a key that makes it easy to remove redundant + // bounds that are constrained by supertraits of the principal def id. + // + // Also make sure we detect conflicting bounds from expanding a trait alias and + // also specifying it manually, like: + // ``` + // type Alias = Trait; + // let _: &dyn Alias = /* ... */; + // ``` + let mut projection_bounds = FxIndexMap::default(); + for (proj, proj_span) in elaborated_projection_bounds { + if let Some((old_proj, old_proj_span)) = projection_bounds.insert( + tcx.anonymize_bound_vars(proj.map_bound(|proj| proj.projection_term)), + (proj, proj_span), + ) && tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj) + { + let item = tcx.item_name(proj.item_def_id()); + self.dcx() + .struct_span_err( + span, + format!( + "conflicting associated type bounds for `{item}` when \ + expanding trait alias" + ), + ) + .with_span_label( + old_proj_span, + format!("`{item}` is specified to be `{}` here", old_proj.term()), + ) + .with_span_label( + proj_span, + format!("`{item}` is specified to be `{}` here", proj.term()), + ) + .emit(); + } + } + // We don't support empty trait objects. if regular_traits.is_empty() && auto_traits.is_empty() { let guar = @@ -105,6 +146,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let principal_trait = regular_traits.into_iter().next(); let mut needed_associated_types = FxIndexSet::default(); + + // These are the projection bounds that we get from supertraits that + // don't mention the dyn trait recursively. See comment below. + let mut implied_projection_bounds = vec![]; + if let Some((principal_trait, spans)) = &principal_trait { let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx); for ClauseWithSupertraitSpan { pred, supertrait_span } in @@ -162,7 +208,34 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // the discussion in #56288 for alternatives. if !references_self { // Include projections defined on supertraits. - projection_bounds.push((pred, supertrait_span)); + implied_projection_bounds.push(pred); + + if let Some((user_written_projection, user_written_span)) = + projection_bounds.shift_remove(&tcx.anonymize_bound_vars( + pred.map_bound(|pred| pred.projection_term), + )) + { + if tcx.anonymize_bound_vars(user_written_projection) + == tcx.anonymize_bound_vars(pred) + { + self.lint_redundant_projection( + hir_id, + user_written_projection, + principal_trait.def_id(), + user_written_span, + supertrait_span, + ); + } else { + self.lint_shadowed_projection( + hir_id, + user_written_projection, + pred, + principal_trait.def_id(), + user_written_span, + supertrait_span, + ); + } + } } self.check_elaborated_projection_mentions_input_lifetimes( @@ -182,12 +255,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // types that we expect to be provided by the user, so the following loop // removes all the associated types that have a corresponding `Projection` // clause, either from expanding trait aliases or written by the user. - for &(projection_bound, span) in &projection_bounds { + for &(projection_bound, span) in projection_bounds.values() { let def_id = projection_bound.item_def_id(); let trait_ref = tcx.anonymize_bound_vars( projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)), ); - needed_associated_types.swap_remove(&(def_id, trait_ref)); + needed_associated_types.shift_remove(&(def_id, trait_ref)); if tcx.generics_require_sized_self(def_id) { tcx.emit_node_span_lint( UNUSED_ASSOCIATED_TYPE_BOUNDS, @@ -197,6 +270,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } } + for projection_bound in &implied_projection_bounds { + let def_id = projection_bound.item_def_id(); + let trait_ref = tcx.anonymize_bound_vars( + projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)), + ); + needed_associated_types.swap_remove(&(def_id, trait_ref)); + } if let Err(guar) = self.check_for_required_assoc_tys( principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()), @@ -266,7 +346,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) }); - let existential_projections = projection_bounds.iter().map(|(bound, _)| { + let existential_projections = projection_bounds.values().map(|(bound, _)| { bound.map_bound(|mut b| { assert_eq!(b.projection_term.self_ty(), dummy_self); @@ -343,6 +423,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_dynamic(tcx, existential_predicates, region_bound, representation) } + fn lint_shadowed_projection( + &self, + hir_id: HirId, + user_written_projection: ty::PolyProjectionPredicate<'tcx>, + elaborated_projection: ty::PolyProjectionPredicate<'tcx>, + principal_def_id: DefId, + user_written_span: Span, + supertrait_span: Span, + ) { + let tcx = self.tcx(); + let assoc = tcx.item_name(user_written_projection.item_def_id()); + let principal = tcx.item_name(principal_def_id); + self.tcx().node_span_lint(DYN_ASSOC_SHADOWED, hir_id, user_written_span, |diag| { + diag.primary_message(format!( + "associated type bound for `{assoc}` in `dyn {principal}` differs from \ + associated type bound from supertrait", + )); + diag.span_label(user_written_span, "this bound has no effect and will be ignored"); + diag.note(format!( + "`{assoc} = {}` was implied by a supertrait and shadows any user-written bounds, \ + so `{assoc} = {}` will be ignored", + elaborated_projection.term(), + user_written_projection.term(), + )); + diag.span_label(supertrait_span, "shadowed due to this supertrait bound"); + }); + } + + fn lint_redundant_projection( + &self, + hir_id: HirId, + user_written_projection: ty::PolyProjectionPredicate<'tcx>, + principal_def_id: DefId, + user_written_span: Span, + supertrait_span: Span, + ) { + let tcx = self.tcx(); + let assoc = tcx.item_name(user_written_projection.item_def_id()); + let principal = tcx.item_name(principal_def_id); + self.tcx().node_span_lint(DYN_ASSOC_REDUNDANT, hir_id, user_written_span, |diag| { + diag.primary_message(format!( + "associated type bound for `{assoc}` in `dyn {principal}` is redundant", + )); + diag.span_label(supertrait_span, "redundant due to this supertrait bound"); + }); + } + /// Check that elaborating the principal of a trait ref doesn't lead to projections /// that are unconstrained. This can happen because an otherwise unconstrained /// *type variable* can be substituted with a type that has late-bound regions. See diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 62dfffb560bac..6c36a5c734152 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -18,7 +18,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::traits::ArgKind; use rustc_trait_selection::traits; -use rustc_type_ir::ClosureKind; +use rustc_type_ir::{ClosureKind, Upcast as _}; use tracing::{debug, instrument, trace}; use super::{CoroutineTypes, Expectation, FnCtxt, check_fn}; @@ -61,6 +61,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(ty) => self.deduce_closure_signature( self.try_structurally_resolve_type(expr_span, ty), closure.kind, + expr_span, ), None => (None, None), }; @@ -301,6 +302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expected_ty: Ty<'tcx>, closure_kind: hir::ClosureKind, + span: Span, ) -> (Option>, Option) { match *expected_ty.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self @@ -312,16 +314,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter_instantiated_copied(self.tcx, args) .map(|(c, s)| (c.as_predicate(), s)), ), - ty::Dynamic(object_type, ..) => { - let sig = object_type.projection_bounds().find_map(|pb| { - let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self); - self.deduce_sig_from_projection(None, closure_kind, pb) - }); - let kind = object_type - .principal_def_id() - .and_then(|did| self.tcx.fn_trait_kind_from_def_id(did)); - (sig, kind) - } + ty::Dynamic(data, ..) => self.deduce_closure_signature_from_predicates( + self.tcx.types.trait_object_dummy_self, + closure_kind, + data.iter().map(|bound| { + ( + bound + .with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self) + .upcast(self.tcx), + span, + ) + }), + ), ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates( Ty::new_var(self.tcx, self.root_var(vid)), closure_kind, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5b4a1f174cbbe..e65646fbedc87 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -39,6 +39,8 @@ declare_lint_pass! { DEPRECATED_SAFE_2024, DEPRECATED_WHERE_CLAUSE_LOCATION, DUPLICATE_MACRO_ATTRIBUTES, + DYN_ASSOC_REDUNDANT, + DYN_ASSOC_SHADOWED, ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, ELIDED_LIFETIMES_IN_PATHS, ELIDED_NAMED_LIFETIMES, @@ -5120,6 +5122,20 @@ declare_lint! { crate_level_only } +declare_lint! { + /// Hi + pub DYN_ASSOC_REDUNDANT, + Warn, + "oops", +} + +declare_lint! { + /// Hi + pub DYN_ASSOC_SHADOWED, + Deny, + "oops", +} + declare_lint! { /// The `abi_unsupported_vector_types` lint detects function definitions and calls /// whose ABI depends on enabling certain target features, but those features are not enabled. diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index afdec7a86d445..5bc2a40016e17 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -80,19 +80,12 @@ impl<'tcx> Relate> for &'tcx ty::List RelateResult<'tcx, Self> { let tcx = relation.cx(); - // FIXME: this is wasteful, but want to do a perf run to see how slow it is. - // We need to perform this deduplication as we sometimes generate duplicate projections - // in `a`. - let mut a_v: Vec<_> = a.into_iter().collect(); - let mut b_v: Vec<_> = b.into_iter().collect(); - a_v.dedup(); - b_v.dedup(); - if a_v.len() != b_v.len() { + if a.len() != b.len() { return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))); } - let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| { - match (ep_a.skip_binder(), ep_b.skip_binder()) { + let v = + iter::zip(a, b).map(|(ep_a, ep_b)| match (ep_a.skip_binder(), ep_b.skip_binder()) { (ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => { Ok(ep_a.rebind(ty::ExistentialPredicate::Trait( relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), @@ -109,8 +102,7 @@ impl<'tcx> Relate> for &'tcx ty::List Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))), _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))), - } - }); + }); tcx.mk_poly_existential_predicates_from_iter(v) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a9a47c87a3882..facbe7525a2bd 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1025,6 +1025,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { fn has_unsafe_fields(self) -> bool { Ty::has_unsafe_fields(self) } + + fn is_self_param(self) -> bool { + self.is_param(0) + } } /// Type utilities diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index d0b01b14d6358..0c82581ad4efd 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -725,6 +725,15 @@ where assumption.upcast(cx), )); } + + for assumption in elaborate::implied_supertrait_projections(cx, principal) { + candidates.extend(G::probe_and_consider_object_bound_candidate( + self, + CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), + goal, + assumption.with_self_ty(cx, self_ty).upcast(cx), + )); + } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 3c5d9b95e772d..6e99e572d0d79 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -3,7 +3,7 @@ use derive_where::derive_where; use rustc_ast_ir::{Movability, Mutability}; -use rustc_type_ir::data_structures::HashMap; +use rustc_type_ir::data_structures::{HashMap, HashSet}; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; @@ -856,6 +856,14 @@ where .map(|(pred, _)| pred), )); + // It's sufficient to just keep track of the def ids of the explicitly specified + // associated types since when users write `dyn Trait`, that associated + // type must resolve to *one* bound from all of the supertraits. So the fact that + // there is a user-provided projection is enough proof that it's unique and we don't + // need to care about substitutions or anything like that. + let specified_associated_projections: HashSet<_> = + object_bounds.projection_bounds().into_iter().map(|proj| proj.item_def_id()).collect(); + // FIXME(associated_const_equality): Also add associated consts to // the requirements here. for associated_type_def_id in cx.associated_type_def_ids(trait_ref.def_id) { @@ -865,6 +873,11 @@ where continue; } + // We don't require these bounds to hold for supertrait implied projection bounds. + if !specified_associated_projections.contains(&associated_type_def_id) { + continue; + } + requirements .extend(cx.item_bounds(associated_type_def_id).iter_instantiated(cx, trait_ref.args)); } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 537b042bde529..f30c6d13a467d 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -51,6 +51,17 @@ pub enum ProjectionError<'tcx> { TraitSelectionError(SelectionError<'tcx>), } +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +enum FromSupertrait { + // Supertrait implied object bound, like `trait IterUnit: Iterator`. + // These will need normalization since they're coming from a query and are thus + // not inherently normalized. + Yes, + // User-written object bound, like: `dyn Iterator`. These will be + // normalized. + No, +} + #[derive(PartialEq, Eq, Debug)] enum ProjectionCandidate<'tcx> { /// From a where-clause in the env or object type @@ -61,7 +72,7 @@ enum ProjectionCandidate<'tcx> { TraitDef(ty::PolyProjectionPredicate<'tcx>), /// Bounds specified on an object type - Object(ty::PolyProjectionPredicate<'tcx>), + Object(ty::PolyProjectionPredicate<'tcx>, FromSupertrait), /// Built-in bound for a dyn async fn in trait ObjectRpitit, @@ -663,7 +674,7 @@ fn project<'cx, 'tcx>( assemble_candidates_from_object_ty(selcx, obligation, &mut candidates); - if let ProjectionCandidateSet::Single(ProjectionCandidate::Object(_)) = candidates { + if let ProjectionCandidateSet::Single(ProjectionCandidate::Object(..)) = candidates { // Avoid normalization cycle from selection (see // `assemble_candidates_from_object_ty`). // FIXME(lazy_normalization): Lazy normalization should save us from @@ -819,20 +830,35 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( } _ => return, }; + let env_predicates = data .projection_bounds() .filter(|bound| bound.item_def_id() == obligation.predicate.def_id) .map(|p| p.with_self_ty(tcx, object_ty).upcast(tcx)); + // Imply projections that come from the object type itself. assemble_candidates_from_predicates( selcx, obligation, candidate_set, - ProjectionCandidate::Object, + |c| ProjectionCandidate::Object(c, FromSupertrait::No), env_predicates, false, ); + // Finally, imply any projections that come from supertrait bounds. + if let Some(principal) = data.principal() { + assemble_candidates_from_predicates( + selcx, + obligation, + candidate_set, + |c| ProjectionCandidate::Object(c, FromSupertrait::Yes), + elaborate::implied_supertrait_projections(tcx, principal) + .map(|pred| pred.with_self_ty(tcx, object_ty).upcast(tcx)), + true, + ); + } + // `dyn Trait` automagically project their AFITs to `dyn* Future`. if tcx.is_impl_trait_in_trait(obligation.predicate.def_id) && let Some(out_trait_def_id) = data.principal_def_id() @@ -1262,10 +1288,15 @@ fn confirm_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { debug!(?obligation, ?candidate, "confirm_candidate"); let mut progress = match candidate { - ProjectionCandidate::ParamEnv(poly_projection) - | ProjectionCandidate::Object(poly_projection) => { + ProjectionCandidate::ParamEnv(poly_projection) => { confirm_param_env_candidate(selcx, obligation, poly_projection, false) } + ProjectionCandidate::Object(poly_projection, from_super) => { + confirm_param_env_candidate(selcx, obligation, poly_projection, match from_super { + FromSupertrait::Yes => true, + FromSupertrait::No => false, + }) + } ProjectionCandidate::TraitDef(poly_projection) => { confirm_param_env_candidate(selcx, obligation, poly_projection, true) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 20b675bcb76b7..06226b366e9e4 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -10,6 +10,7 @@ use rustc_middle::ty::{ }; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_span::{DUMMY_SP, Span}; +use rustc_type_ir::elaborate; use tracing::{debug, instrument, trace}; use crate::infer::InferCtxt; @@ -856,6 +857,17 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { )); } } + + // Finally, for backwards compatibility reasons, we imply the outlives bounds + // that come from supertrait projections since we used to elaborate them into + // the dyn trait itself. + // + // See when this was changed. + if let Some(principal) = data.principal() { + for projection in elaborate::implied_supertrait_projections(tcx, principal) { + projection.visit_with(self); + } + } } // Inference variables are the complicated case, since we don't diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 923b74abdfd2f..c8a35bb4f7311 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -1,11 +1,13 @@ use std::marker::PhantomData; +use std::ops::ControlFlow; use smallvec::smallvec; use crate::data_structures::HashSet; use crate::inherent::*; use crate::outlives::{Component, push_outlives_components}; -use crate::{self as ty, Interner, Upcast as _}; +use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; +use crate::{self as ty, Interner, TypeFlags, Upcast as _}; /// "Elaboration" is the process of identifying all the predicates that /// are implied by a source predicate. Currently, this basically means @@ -337,3 +339,48 @@ impl> Iterator for FilterToTraits( + cx: I, + principal: ty::Binder>, +) -> impl Iterator>> { + // We check that the predicates don't mention self, so we + // don't care about what self type we substitute here, + // since we immediately erase it anyways. + let principal = principal.with_self_ty(cx, Ty::new_unit(cx)); + + // Make sure we only elaborate one copy of every projection (modulo bound vars) + let mut seen = HashSet::default(); + + let clause: I::Clause = ty::TraitRef::identity(cx, principal.def_id()).upcast(cx); + elaborate(cx, [clause]) + .filter_only_self() + .filter(move |clause| { + clause.as_projection_clause().is_some_and(|proj_pred| { + proj_pred.term().visit_with(&mut MentionsSelf).is_continue() + }) + }) + .map(move |clause| clause.instantiate_supertrait(cx, principal)) + .map(move |clause| { + clause + .as_projection_clause() + .unwrap() + .map_bound(|proj| ty::ExistentialProjection::erase_self_ty(cx, proj)) + }) + .filter(move |proj_pred| seen.insert(cx.anonymize_bound_vars(*proj_pred))) +} + +struct MentionsSelf; +impl TypeVisitor for MentionsSelf { + type Result = ControlFlow<()>; + + fn visit_ty(&mut self, ty: I::Ty) -> Self::Result { + if ty.is_self_param() { + ControlFlow::Break(()) + } else if ty.has_type_flags(TypeFlags::HAS_TY_PARAM) { + ty.super_visit_with(self) + } else { + ControlFlow::Continue(()) + } + } +} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 872cf6680185b..8ba1f5d841043 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -141,6 +141,8 @@ pub trait Ty>: /// Checks whether this type is an ADT that has unsafe fields. fn has_unsafe_fields(self) -> bool; + fn is_self_param(self) -> bool; + fn fn_sig(self, interner: I) -> ty::Binder> { match self.kind() { ty::FnPtr(sig_tys, hdr) => sig_tys.with(hdr), diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index d66ba157d1068..8c9e8570b3bbd 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1658; +const ISSUES_ENTRY_LIMIT: u32 = 1660; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/crashes/125957.rs b/tests/crashes/125957.rs deleted file mode 100644 index e3abe5262eb90..0000000000000 --- a/tests/crashes/125957.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: rust-lang/rust#125957 -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] -#![feature(associated_const_equality)] - -pub struct Equal(); - -pub enum ParseMode { - Raw, -} -pub trait Parse { - const PARSE_MODE: ParseMode; -} -pub trait RenderRaw: Parse {} - -trait GenericVec { - fn unwrap() -> dyn RenderRaw; -} - -fn main() {} diff --git a/tests/crashes/132330.rs b/tests/crashes/132330.rs deleted file mode 100644 index 3432685749d9d..0000000000000 --- a/tests/crashes/132330.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ known-bug: #132330 -//@compile-flags: -Znext-solver=globally - -trait Service { - type S; -} - -trait Framing { - type F; -} - -impl Framing for () { - type F = (); -} - -trait HttpService: Service {} - -type BoxService = Box>; - -fn build_server BoxService>(_: F) {} - -fn make_server() -> Box> { - unimplemented!() -} - -fn main() { - build_server(|| make_server()) -} diff --git a/tests/ui/associated-types/associated-types-overridden-binding-2.rs b/tests/ui/associated-types/associated-types-overridden-binding-2.rs index fed60ccf089d0..247724eaaf112 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding-2.rs +++ b/tests/ui/associated-types/associated-types-overridden-binding-2.rs @@ -4,5 +4,5 @@ trait I32Iterator = Iterator; fn main() { let _: &dyn I32Iterator = &vec![42].into_iter(); - //~^ ERROR expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` + //~^ ERROR conflicting associated type bounds } diff --git a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr index 4dfd275a19058..71a4a2610aac4 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -1,11 +1,13 @@ -error[E0271]: expected `IntoIter` to be an iterator that yields `i32`, but it yields `u32` - --> $DIR/associated-types-overridden-binding-2.rs:6:43 +error: conflicting associated type bounds for `Item` when expanding trait alias + --> $DIR/associated-types-overridden-binding-2.rs:6:13 | +LL | trait I32Iterator = Iterator; + | ---------- `Item` is specified to be `i32` here +... LL | let _: &dyn I32Iterator = &vec![42].into_iter(); - | ^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` - | - = note: required for the cast from `&std::vec::IntoIter` to `&dyn Iterator` + | ^^^^^^^^^^^^^^^^----------^ + | | + | `Item` is specified to be `u32` here error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/associated-types/associated-types-overridden-binding.rs b/tests/ui/associated-types/associated-types-overridden-binding.rs index 9a64a06c31bad..333a3e30c7dcf 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding.rs +++ b/tests/ui/associated-types/associated-types-overridden-binding.rs @@ -8,4 +8,5 @@ trait U32Iterator = I32Iterator; //~ ERROR type annotations needed fn main() { let _: &dyn I32Iterator; + //~^ ERROR conflicting associated type bounds } diff --git a/tests/ui/associated-types/associated-types-overridden-binding.stderr b/tests/ui/associated-types/associated-types-overridden-binding.stderr index dc087e4185fb6..3b20015dfcab3 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding.stderr +++ b/tests/ui/associated-types/associated-types-overridden-binding.stderr @@ -22,6 +22,17 @@ note: required by a bound in `I32Iterator` LL | trait I32Iterator = Iterator; | ^^^^^^^^^^ required by this bound in `I32Iterator` -error: aborting due to 2 previous errors +error: conflicting associated type bounds for `Item` when expanding trait alias + --> $DIR/associated-types-overridden-binding.rs:10:13 + | +LL | trait I32Iterator = Iterator; + | ---------- `Item` is specified to be `i32` here +... +LL | let _: &dyn I32Iterator; + | ^^^^^^^^^^^^^^^^----------^ + | | + | `Item` is specified to be `u32` here + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/associated-types/issue-59324.rs b/tests/ui/associated-types/issue-59324.rs index 7421e08c89888..a05789c616cb3 100644 --- a/tests/ui/associated-types/issue-59324.rs +++ b/tests/ui/associated-types/issue-59324.rs @@ -21,8 +21,7 @@ pub trait ThriftService: } fn with_factory(factory: dyn ThriftService<()>) {} -//~^ ERROR the trait bound `(): Foo` is not satisfied +//~^ ERROR cannot be known at compilation time //~| ERROR the trait bound `(): Foo` is not satisfied -//~| ERROR cannot be known at compilation time fn main() {} diff --git a/tests/ui/associated-types/issue-59324.stderr b/tests/ui/associated-types/issue-59324.stderr index 2abe337b69ae3..096434ae47384 100644 --- a/tests/ui/associated-types/issue-59324.stderr +++ b/tests/ui/associated-types/issue-59324.stderr @@ -64,26 +64,13 @@ help: consider further restricting type parameter `Bug` with trait `Foo` LL | pub trait ThriftService: | +++++ -error[E0277]: the trait bound `(): Foo` is not satisfied - --> $DIR/issue-59324.rs:23:29 - | -LL | fn with_factory(factory: dyn ThriftService<()>) {} - | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` - | -help: this trait has no implementations, consider adding one - --> $DIR/issue-59324.rs:3:1 - | -LL | pub trait Foo: NotFoo { - | ^^^^^^^^^^^^^^^^^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0277]: the size for values of type `(dyn ThriftService<(), AssocType = _> + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn ThriftService<()> + 'static)` cannot be known at compilation time --> $DIR/issue-59324.rs:23:29 | LL | fn with_factory(factory: dyn ThriftService<()>) {} | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `(dyn ThriftService<(), AssocType = _> + 'static)` + = help: the trait `Sized` is not implemented for `(dyn ThriftService<()> + 'static)` = help: unsized fn params are gated as an unstable feature help: you can use `impl Trait` as the argument type | @@ -94,6 +81,6 @@ help: function arguments must have a statically known size, borrowed types alway LL | fn with_factory(factory: &dyn ThriftService<()>) {} | + -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/closures/deduce-from-object-supertrait.rs b/tests/ui/closures/deduce-from-object-supertrait.rs new file mode 100644 index 0000000000000..315d90c4c5086 --- /dev/null +++ b/tests/ui/closures/deduce-from-object-supertrait.rs @@ -0,0 +1,15 @@ +//@ check-pass + +trait Foo: Fn(Bar) {} +impl Foo for T where T: Fn(Bar) {} + +struct Bar; +impl Bar { + fn bar(&self) {} +} + +fn main() { + let x: &dyn Foo = &|x| { + x.bar(); + }; +} diff --git a/tests/ui/dyn-compatibility/multiple-supers-should-work.rs b/tests/ui/dyn-compatibility/multiple-supers-should-work.rs new file mode 100644 index 0000000000000..355089b9a9d89 --- /dev/null +++ b/tests/ui/dyn-compatibility/multiple-supers-should-work.rs @@ -0,0 +1,18 @@ +//@ check-pass + +trait Sup { + type Assoc; +} + +impl Sup for () { + type Assoc = T; +} + +trait Trait: Sup + Sup {} + +impl Trait for () {} + +fn main() { + let x: &dyn Trait<(), _> = &(); + let y: &dyn Trait<_, ()> = x; +} diff --git a/tests/ui/issues/issue-57156.rs b/tests/ui/issues/issue-57156.rs index 12251509abd2d..0a6023d70831b 100644 --- a/tests/ui/issues/issue-57156.rs +++ b/tests/ui/issues/issue-57156.rs @@ -6,6 +6,7 @@ trait Foo { trait Bar<'a, T>: for<'s> Foo<&'s T, Output=bool> { fn cb(&self) -> Box>; + //~^ WARN associated type bound for `Output` in `dyn Bar` is redundant } impl<'s> Foo<&'s ()> for () { @@ -14,6 +15,7 @@ impl<'s> Foo<&'s ()> for () { impl<'a> Bar<'a, ()> for () { fn cb(&self) -> Box> { + //~^ WARN associated type bound for `Output` in `dyn Bar` is redundant Box::new(*self) } } diff --git a/tests/ui/issues/issue-57156.stderr b/tests/ui/issues/issue-57156.stderr new file mode 100644 index 0000000000000..e9072e203fb7c --- /dev/null +++ b/tests/ui/issues/issue-57156.stderr @@ -0,0 +1,21 @@ +warning: associated type bound for `Output` in `dyn Bar` is redundant + --> $DIR/issue-57156.rs:8:40 + | +LL | trait Bar<'a, T>: for<'s> Foo<&'s T, Output=bool> { + | ----------- redundant due to this supertrait bound +LL | fn cb(&self) -> Box>; + | ^^^^^^^^^^^ + | + = note: `#[warn(dyn_assoc_redundant)]` on by default + +warning: associated type bound for `Output` in `dyn Bar` is redundant + --> $DIR/issue-57156.rs:17:41 + | +LL | trait Bar<'a, T>: for<'s> Foo<&'s T, Output=bool> { + | ----------- redundant due to this supertrait bound +... +LL | fn cb(&self) -> Box> { + | ^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/issues/issue-59326.rs b/tests/ui/issues/issue-59326.rs index e9634ad9fd8fe..19c6d10941471 100644 --- a/tests/ui/issues/issue-59326.rs +++ b/tests/ui/issues/issue-59326.rs @@ -1,4 +1,3 @@ -//@ check-pass trait Service { type S; } @@ -14,10 +13,12 @@ impl Framing for () { trait HttpService: Service {} type BoxService = Box>; +//~^ ERROR associated type bound for `S` in `dyn HttpService` differs from associated type bound from supertrait fn build_server BoxService>(_: F) {} fn make_server() -> Box> { + //~^ WARN associated type bound for `S` in `dyn HttpService` is redundant unimplemented!() } diff --git a/tests/ui/issues/issue-59326.stderr b/tests/ui/issues/issue-59326.stderr new file mode 100644 index 0000000000000..ebeee1e2f4696 --- /dev/null +++ b/tests/ui/issues/issue-59326.stderr @@ -0,0 +1,25 @@ +error: associated type bound for `S` in `dyn HttpService` differs from associated type bound from supertrait + --> $DIR/issue-59326.rs:15:43 + | +LL | trait HttpService: Service {} + | -------- shadowed due to this supertrait bound +LL | +LL | type BoxService = Box>; + | ^^^^^^ this bound has no effect and will be ignored + | + = note: `S = <() as Framing>::F` was implied by a supertrait and shadows any user-written bounds, so `S = ()` will be ignored + = note: `#[deny(dyn_assoc_shadowed)]` on by default + +warning: associated type bound for `S` in `dyn HttpService` is redundant + --> $DIR/issue-59326.rs:20:56 + | +LL | trait HttpService: Service {} + | -------- redundant due to this supertrait bound +... +LL | fn make_server() -> Box> { + | ^^^^^^^^ + | + = note: `#[warn(dyn_assoc_redundant)]` on by default + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/tests/crashes/126944.rs b/tests/ui/traits/object/crash-due-to-projections-modulo-norm.rs similarity index 63% rename from tests/crashes/126944.rs rename to tests/ui/traits/object/crash-due-to-projections-modulo-norm.rs index c0c5622e26020..7461e2b4e2f32 100644 --- a/tests/crashes/126944.rs +++ b/tests/ui/traits/object/crash-due-to-projections-modulo-norm.rs @@ -1,9 +1,8 @@ -//@ known-bug: rust-lang/rust#126944 // Step 1: Create two names for a single type: `Thing` and `AlsoThing` struct Thing; struct Dummy; -pub trait DummyTrait { +trait DummyTrait { type DummyType; } impl DummyTrait for Dummy { @@ -13,7 +12,7 @@ type AlsoThing = ::DummyType; // Step 2: Create names for a single trait object type: `TraitObject` and `AlsoTraitObject` -pub trait SomeTrait { +trait SomeTrait { type Item; } type TraitObject = dyn SomeTrait; @@ -21,18 +20,22 @@ type AlsoTraitObject = dyn SomeTrait; // Step 3: Force the compiler to check whether the two names are the same type -pub trait Supertrait { +trait Supertrait { type Foo; } -pub trait Subtrait: Supertrait {} +trait Subtrait: Supertrait {} -pub trait HasOutput { +trait HasOutput { type Output; } fn foo() -> F::Output where F: HasOutput>, -{ + //~^ ERROR associated type bound for `Foo` in `dyn Subtrait` differs from associated type bound from supertrait + //~| ERROR associated type bound for `Foo` in `dyn Subtrait` differs from associated type bound from supertrait + { todo!() } + +fn main() {} diff --git a/tests/ui/traits/object/crash-due-to-projections-modulo-norm.stderr b/tests/ui/traits/object/crash-due-to-projections-modulo-norm.stderr new file mode 100644 index 0000000000000..f0cfe5287737c --- /dev/null +++ b/tests/ui/traits/object/crash-due-to-projections-modulo-norm.stderr @@ -0,0 +1,26 @@ +error: associated type bound for `Foo` in `dyn Subtrait` differs from associated type bound from supertrait + --> $DIR/crash-due-to-projections-modulo-norm.rs:34:31 + | +LL | trait Subtrait: Supertrait {} + | ----------------- shadowed due to this supertrait bound +... +LL | F: HasOutput>, + | ^^^^^^^^^^^^^^^^^^^^^ this bound has no effect and will be ignored + | + = note: `Foo = (dyn SomeTrait::DummyType> + 'static)` was implied by a supertrait and shadows any user-written bounds, so `Foo = (dyn SomeTrait + 'static)` will be ignored + = note: `#[deny(dyn_assoc_shadowed)]` on by default + +error: associated type bound for `Foo` in `dyn Subtrait` differs from associated type bound from supertrait + --> $DIR/crash-due-to-projections-modulo-norm.rs:34:31 + | +LL | trait Subtrait: Supertrait {} + | ----------------- shadowed due to this supertrait bound +... +LL | F: HasOutput>, + | ^^^^^^^^^^^^^^^^^^^^^ this bound has no effect and will be ignored + | + = note: `Foo = (dyn SomeTrait::DummyType> + 'static)` was implied by a supertrait and shadows any user-written bounds, so `Foo = (dyn SomeTrait + 'static)` will be ignored + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/traits/object/incomplete-multiple-super-projection.rs b/tests/ui/traits/object/incomplete-multiple-super-projection.rs new file mode 100644 index 0000000000000..c9f099b9a36de --- /dev/null +++ b/tests/ui/traits/object/incomplete-multiple-super-projection.rs @@ -0,0 +1,30 @@ +trait Sup { + type Assoc; +} + +impl Sup for () { + type Assoc = T; +} +impl Dyn for () {} + +trait Dyn: Sup + Sup {} + +trait Trait { + type Assoc; +} +impl Trait for dyn Dyn<(), ()> { + type Assoc = &'static str; +} +impl Trait for dyn Dyn { +//~^ ERROR conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)` + type Assoc = usize; +} + +fn call(x: usize) -> as Trait>::Assoc { + x +} + +fn main() { + let x: &'static str = call::<(), ()>(0xDEADBEEF); + println!("{x}"); +} diff --git a/tests/ui/traits/object/incomplete-multiple-super-projection.stderr b/tests/ui/traits/object/incomplete-multiple-super-projection.stderr new file mode 100644 index 0000000000000..90ad9e3272186 --- /dev/null +++ b/tests/ui/traits/object/incomplete-multiple-super-projection.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `(dyn Dyn<(), ()> + 'static)` + --> $DIR/incomplete-multiple-super-projection.rs:18:1 + | +LL | impl Trait for dyn Dyn<(), ()> { + | ------------------------------ first implementation here +... +LL | impl Trait for dyn Dyn { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Dyn<(), ()> + 'static)` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/crashes/79590.rs b/tests/ui/traits/object/infer-shadows-implied-projection.rs similarity index 100% rename from tests/crashes/79590.rs rename to tests/ui/traits/object/infer-shadows-implied-projection.rs diff --git a/tests/ui/traits/object/infer-shadows-implied-projection.stderr b/tests/ui/traits/object/infer-shadows-implied-projection.stderr new file mode 100644 index 0000000000000..fa40a2ca5e9ca --- /dev/null +++ b/tests/ui/traits/object/infer-shadows-implied-projection.stderr @@ -0,0 +1,21 @@ +error: associated type bound for `Inner` in `dyn Database` differs from associated type bound from supertrait + --> $DIR/infer-shadows-implied-projection.rs:18:26 + | +LL | trait Database: Restriction {} + | ----------- shadowed due to this supertrait bound +... +LL | let x: &dyn Database = &t; + | ^^^^^^^^^ this bound has no effect and will be ignored + | + = note: `Inner = u32` was implied by a supertrait and shadows any user-written bounds, so `Inner = _` will be ignored + = note: `#[deny(dyn_assoc_shadowed)]` on by default + +error[E0282]: type annotations needed + --> $DIR/infer-shadows-implied-projection.rs:18:34 + | +LL | let x: &dyn Database = &t; + | ^ cannot infer type + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/object/outlives-super-proj.rs b/tests/ui/traits/object/outlives-super-proj.rs new file mode 100644 index 0000000000000..15b67d9ab68e7 --- /dev/null +++ b/tests/ui/traits/object/outlives-super-proj.rs @@ -0,0 +1,24 @@ +//@ check-pass + +// Make sure that we still deduce outlives bounds from supertrait projections +// and require them for well-formedness. + +trait Trait { + type Assoc; +} + +trait Bar { + type Assoc; +} + +trait Foo<'a, T: 'a>: Bar { + +} + +fn outlives<'a, T: 'a>() {} + +fn implied_outlives<'a, T: Trait>(x: &dyn Foo<'a, T::Assoc>) { + outlives::<'a, T::Assoc>(); +} + +fn main() {} diff --git a/tests/ui/traits/object/pretty.rs b/tests/ui/traits/object/pretty.rs index 603d7af526002..eaf4e1b58c800 100644 --- a/tests/ui/traits/object/pretty.rs +++ b/tests/ui/traits/object/pretty.rs @@ -26,6 +26,7 @@ fn dyn_super(x: &dyn Super) { x } //~ERROR mismatched types fn dyn_any(x: &dyn Any) { x } //~ERROR mismatched types fn dyn_fixed(x: &dyn Fixed) { x } //~ERROR mismatched types fn dyn_fixed_multi(x: &dyn Fixed) { x } //~ERROR mismatched types +//~^ ERROR associated type bound for `Assoc` in `dyn Fixed` differs from associated type bound from supertrait fn dyn_fixed_sub(x: &dyn FixedSub) { x } //~ERROR mismatched types fn dyn_fixed_static(x: &dyn FixedStatic) { x } //~ERROR mismatched types @@ -34,6 +35,7 @@ fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } //~ERR fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } //~ERROR mismatched types // fn dyn_fixed_generic2(x: &dyn for<'a> FixedGeneric2<'a>) { x } // Unsound! fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } //~ERROR mismatched types +//~^ ERROR associated type bound for `Assoc2` in `dyn FixedGeneric1` differs from associated type bound from supertrait fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } //~ERROR mismatched types fn dyn_any_different_binders(x: &dyn AnyDifferentBinders) { x } //~ERROR mismatched types fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x } //~ERROR mismatched types diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr index af941e69c5f84..4b921582ae6c1 100644 --- a/tests/ui/traits/object/pretty.stderr +++ b/tests/ui/traits/object/pretty.stderr @@ -1,5 +1,28 @@ +error: associated type bound for `Assoc` in `dyn Fixed` differs from associated type bound from supertrait + --> $DIR/pretty.rs:28:34 + | +LL | trait Fixed: Super {} + | ---------- shadowed due to this supertrait bound +... +LL | fn dyn_fixed_multi(x: &dyn Fixed) { x } + | ^^^^^^^^^^^ this bound has no effect and will be ignored + | + = note: `Assoc = u8` was implied by a supertrait and shadows any user-written bounds, so `Assoc = u16` will be ignored + = note: `#[deny(dyn_assoc_shadowed)]` on by default + +error: associated type bound for `Assoc2` in `dyn FixedGeneric1` differs from associated type bound from supertrait + --> $DIR/pretty.rs:37:62 + | +LL | trait FixedGeneric1<'a>: SuperGeneric<'a, Assoc2 = &'a u8> {} + | --------------- shadowed due to this supertrait bound +... +LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } + | ^^^^^^^^^^^^ this bound has no effect and will be ignored + | + = note: `Assoc2 = for<'a> &'a u8` was implied by a supertrait and shadows any user-written bounds, so `Assoc2 = &'a u8` will be ignored + warning: unnecessary associated type bound for dyn-incompatible associated type - --> $DIR/pretty.rs:41:35 + --> $DIR/pretty.rs:43:35 | LL | fn dyn_has_gat(x: &dyn HasGat = ()>) { x } | ^^^^^^^^^^^^^^^^ help: remove this bound @@ -44,15 +67,15 @@ error[E0308]: mismatched types --> $DIR/pretty.rs:28:50 | LL | fn dyn_fixed_multi(x: &dyn Fixed) { x } - | - ^ expected `()`, found `&dyn Fixed` + | - ^ expected `()`, found `&dyn Fixed` | | - | help: try adding a return type: `-> &dyn Fixed` + | help: try adding a return type: `-> &dyn Fixed` | = note: expected unit type `()` - found reference `&dyn Fixed` + found reference `&dyn Fixed` error[E0308]: mismatched types - --> $DIR/pretty.rs:29:38 + --> $DIR/pretty.rs:30:38 | LL | fn dyn_fixed_sub(x: &dyn FixedSub) { x } | - ^ expected `()`, found `&dyn FixedSub` @@ -63,7 +86,7 @@ LL | fn dyn_fixed_sub(x: &dyn FixedSub) { x } found reference `&dyn FixedSub` error[E0308]: mismatched types - --> $DIR/pretty.rs:30:44 + --> $DIR/pretty.rs:31:44 | LL | fn dyn_fixed_static(x: &dyn FixedStatic) { x } | - ^ expected `()`, found `&dyn FixedStatic` @@ -74,7 +97,7 @@ LL | fn dyn_fixed_static(x: &dyn FixedStatic) { x } found reference `&dyn FixedStatic` error[E0308]: mismatched types - --> $DIR/pretty.rs:32:75 + --> $DIR/pretty.rs:33:75 | LL | fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x } | - ^ expected `()`, found `&dyn SuperGeneric<'a, Assoc2 = &u8>` @@ -85,7 +108,7 @@ LL | fn dyn_super_generic(x: &dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>) { x found reference `&dyn for<'a> SuperGeneric<'a, Assoc2 = &'a u8>` error[E0308]: mismatched types - --> $DIR/pretty.rs:33:71 + --> $DIR/pretty.rs:34:71 | LL | fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } | - ^ expected `()`, found `&dyn AnyGeneric<'a, Assoc2 = &u8>` @@ -96,7 +119,7 @@ LL | fn dyn_any_generic(x: &dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>) { x } found reference `&dyn for<'a> AnyGeneric<'a, Assoc2 = &'a u8>` error[E0308]: mismatched types - --> $DIR/pretty.rs:34:60 + --> $DIR/pretty.rs:35:60 | LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } | - ^ expected `()`, found `&dyn FixedGeneric1<'a>` @@ -107,18 +130,18 @@ LL | fn dyn_fixed_generic1(x: &dyn for<'a> FixedGeneric1<'a>) { x } found reference `&dyn for<'a> FixedGeneric1<'a>` error[E0308]: mismatched types - --> $DIR/pretty.rs:36:79 + --> $DIR/pretty.rs:37:79 | LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } - | - ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = ...>` + | - ^ expected `()`, found `&dyn FixedGeneric1<'a>` | | - | help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>` + | help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a>` | = note: expected unit type `()` - found reference `&dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>` + found reference `&dyn for<'a> FixedGeneric1<'a>` error[E0308]: mismatched types - --> $DIR/pretty.rs:37:40 + --> $DIR/pretty.rs:39:40 | LL | fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } | - ^ expected `()`, found `&dyn FixedHrtb` @@ -129,7 +152,7 @@ LL | fn dyn_fixed_hrtb(x: &dyn FixedHrtb) { x } found reference `&dyn FixedHrtb` error[E0308]: mismatched types - --> $DIR/pretty.rs:38:73 + --> $DIR/pretty.rs:40:73 | LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders) { x } | - ^ expected `()`, found `&dyn AnyDifferentBinders` @@ -140,7 +163,7 @@ LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders) { x } found reference `&dyn AnyDifferentBinders` error[E0308]: mismatched types - --> $DIR/pretty.rs:39:65 + --> $DIR/pretty.rs:41:65 | LL | fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x } | - ^ expected `()`, found `&dyn FixedDifferentBinders` @@ -151,7 +174,7 @@ LL | fn dyn_fixed_different_binders(x: &dyn FixedDifferentBinders) { x } found reference `&dyn FixedDifferentBinders` error[E0308]: mismatched types - --> $DIR/pretty.rs:41:56 + --> $DIR/pretty.rs:43:56 | LL | fn dyn_has_gat(x: &dyn HasGat = ()>) { x } | - ^ expected `()`, found `&dyn HasGat = ()>` @@ -161,6 +184,6 @@ LL | fn dyn_has_gat(x: &dyn HasGat = ()>) { x } = note: expected unit type `()` found reference `&dyn HasGat = ()>` -error: aborting due to 14 previous errors; 1 warning emitted +error: aborting due to 16 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/object/redundant.rs b/tests/ui/traits/object/redundant.rs new file mode 100644 index 0000000000000..0bbab092daca0 --- /dev/null +++ b/tests/ui/traits/object/redundant.rs @@ -0,0 +1,13 @@ +//@ check-pass + +trait Foo: Bar {} +trait Bar { + type Out; +} + +fn w(x: &dyn Foo) { + //~^ WARN associated type bound for `Out` in `dyn Foo` is redundant + let x: &dyn Foo = x; +} + +fn main() {} diff --git a/tests/ui/traits/object/redundant.stderr b/tests/ui/traits/object/redundant.stderr new file mode 100644 index 0000000000000..fe8d467a7ff78 --- /dev/null +++ b/tests/ui/traits/object/redundant.stderr @@ -0,0 +1,13 @@ +warning: associated type bound for `Out` in `dyn Foo` is redundant + --> $DIR/redundant.rs:8:18 + | +LL | trait Foo: Bar {} + | -------- redundant due to this supertrait bound +... +LL | fn w(x: &dyn Foo) { + | ^^^^^^^^ + | + = note: `#[warn(dyn_assoc_redundant)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs index 2d8230973325d..61d6859878c41 100644 --- a/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs +++ b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.rs @@ -48,4 +48,5 @@ fn main() { // being specified. let _x: Box> = Box::new(2u32); let _y: Box> = Box::new(2u32); + //~^ WARN associated type bound for `Output` in `dyn NormalizingHelper` is redundant } diff --git a/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.stderr b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.stderr new file mode 100644 index 0000000000000..affdaa798037c --- /dev/null +++ b/tests/ui/traits/object/with-self-in-projection-output-repeated-supertrait.stderr @@ -0,0 +1,13 @@ +warning: associated type bound for `Output` in `dyn NormalizingHelper` is redundant + --> $DIR/with-self-in-projection-output-repeated-supertrait.rs:50:51 + | +LL | trait NormalizingHelper: Base::Out> + Base { + | ---------- redundant due to this supertrait bound +... +LL | let _y: Box> = Box::new(2u32); + | ^^^^^^^^^^ + | + = note: `#[warn(dyn_assoc_redundant)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/wf/hir-wf-canonicalized.rs b/tests/ui/wf/hir-wf-canonicalized.rs index abdcd1c04ab2a..dc80a7c795f71 100644 --- a/tests/ui/wf/hir-wf-canonicalized.rs +++ b/tests/ui/wf/hir-wf-canonicalized.rs @@ -9,8 +9,8 @@ trait Callback: Fn(&Bar<'_, T>, &T::V) {} struct Bar<'a, T> { callback: Box>>>, //~^ ERROR the trait bound `Bar<'a, T>: Foo` is not satisfied - //~| ERROR the trait bound `(dyn Callback, Output = ()> + 'static): Foo` is not satisfied - //~| ERROR the size for values of type `(dyn Callback, Output = ()> + 'static)` cannot be known at compilation time + //~| ERROR the trait bound `(dyn Callback> + 'static): Foo` is not satisfied + //~| ERROR the size for values of type `(dyn Callback> + 'static)` cannot be known at compilation time } impl Bar<'_, Bar<'_, T>> {} diff --git a/tests/ui/wf/hir-wf-canonicalized.stderr b/tests/ui/wf/hir-wf-canonicalized.stderr index 8938801ce3d97..434a1d6de238a 100644 --- a/tests/ui/wf/hir-wf-canonicalized.stderr +++ b/tests/ui/wf/hir-wf-canonicalized.stderr @@ -10,11 +10,11 @@ help: this trait has no implementations, consider adding one LL | trait Foo { | ^^^^^^^^^ -error[E0277]: the trait bound `(dyn Callback, Output = ()> + 'static): Foo` is not satisfied +error[E0277]: the trait bound `(dyn Callback> + 'static): Foo` is not satisfied --> $DIR/hir-wf-canonicalized.rs:10:15 | LL | callback: Box>>>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback, Output = ()> + 'static)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(dyn Callback> + 'static)` | help: this trait has no implementations, consider adding one --> $DIR/hir-wf-canonicalized.rs:3:1 @@ -22,13 +22,13 @@ help: this trait has no implementations, consider adding one LL | trait Foo { | ^^^^^^^^^ -error[E0277]: the size for values of type `(dyn Callback, Output = ()> + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Callback> + 'static)` cannot be known at compilation time --> $DIR/hir-wf-canonicalized.rs:10:15 | LL | callback: Box>>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `(dyn Callback, Output = ()> + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Callback> + 'static)` note: required by an implicit `Sized` bound in `Bar` --> $DIR/hir-wf-canonicalized.rs:9:16 |