Rollup merge of #146664 - fmease:clean-up-dyn, r=jdonszelmann

Clean up `ty::Dynamic`

1. As a follow-up to PR rust-lang/rust#143036, remove `DynKind` entirely.
2. Inside HIR ty lowering, consolidate modules `dyn_compatibility` and `lint` into `dyn_trait`
   * `dyn_compatibility` wasn't about dyn compatibility itself, it's about lowering trait object types
   * `lint` contained dyn-Trait-specific diagnostics+lints only
This commit is contained in:
Stuart Cook 2025-09-18 11:48:51 +10:00 committed by GitHub
commit 540fd20ba6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
75 changed files with 691 additions and 786 deletions

View file

@ -438,7 +438,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
let elaborated_args =
std::iter::zip(*args, &generics.own_params).map(|(arg, param)| {
if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
if let Some(ty::Dynamic(obj, _)) = arg.as_type().map(Ty::kind) {
let default = tcx.object_lifetime_default(param.def_id);
let re_static = tcx.lifetimes.re_static;
@ -464,7 +464,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
has_dyn = true;
Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
Ty::new_dynamic(tcx, obj, implied_region).into()
} else {
arg
}

View file

@ -1903,7 +1903,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
@ -1949,7 +1949,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::CoroutineWitness(..)
| ty::Never
| ty::UnsafeBinder(_)

View file

@ -1487,9 +1487,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
unsize_to: None,
},
);
} else if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) =
} else if let ty::Dynamic(src_tty, _src_lt) =
*self.struct_tail(src.ty, location).kind()
&& let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) =
&& let ty::Dynamic(dst_tty, dst_lt) =
*self.struct_tail(dst.ty, location).kind()
&& src_tty.principal().is_some()
&& dst_tty.principal().is_some()
@ -1511,7 +1511,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// FIXME: Once we disallow casting `*const dyn Trait + 'short`
// to `*const dyn Trait + 'long`, then this can just be `src_lt`.
dst_lt,
ty::Dyn,
);
let dst_obj = Ty::new_dynamic(
tcx,
@ -1519,7 +1518,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
&dst_tty.without_auto_traits().collect::<Vec<_>>(),
),
dst_lt,
ty::Dyn,
);
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);

View file

@ -715,7 +715,7 @@ pub(crate) fn codegen_drop<'tcx>(
fx.bcx.ins().jump(ret_block, &[]);
} else {
match ty.kind() {
ty::Dynamic(_, _, ty::Dyn) => {
ty::Dynamic(_, _) => {
// IN THIS ARM, WE HAVE:
// ty = *mut (dyn Trait)
// which is: exists<T> ( *mut T, Vtable<T: Trait> )

View file

@ -30,9 +30,7 @@ pub(crate) fn unsized_info<'tcx>(
fx.pointer_type,
len.try_to_target_usize(fx.tcx).expect("expected monomorphic const in codegen") as i64,
),
(&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind))
if src_dyn_kind == target_dyn_kind =>
{
(&ty::Dynamic(data_a, _), &ty::Dynamic(data_b, _)) => {
let old_info =
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
let b_principal_def_id = data_b.principal_def_id();

View file

@ -909,8 +909,7 @@ pub(crate) fn assert_assignable<'tcx>(
);
// fn(&T) -> for<'l> fn(&'l T) is allowed
}
(&ty::Dynamic(from_traits, _, _from_kind), &ty::Dynamic(to_traits, _, _to_kind)) => {
// FIXME(dyn-star): Do the right thing with DynKinds
(&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => {
for (from, to) in from_traits.iter().zip(to_traits) {
let from = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), from);
let to = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), to);

View file

@ -168,9 +168,7 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
(&ty::Array(_, len), &ty::Slice(_)) => cx.const_usize(
len.try_to_target_usize(cx.tcx()).expect("expected monomorphic const in codegen"),
),
(&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind))
if src_dyn_kind == target_dyn_kind =>
{
(&ty::Dynamic(data_a, _), &ty::Dynamic(data_b, _)) => {
let old_info =
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
let b_principal_def_id = data_b.principal_def_id();
@ -208,7 +206,7 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
old_info
}
}
(_, ty::Dynamic(data, _, _)) => meth::get_vtable(
(_, ty::Dynamic(data, _)) => meth::get_vtable(
cx,
source,
data.principal()

View file

@ -78,7 +78,7 @@ fn dyn_trait_in_self<'tcx>(
) -> Option<ty::ExistentialTraitRef<'tcx>> {
for arg in ty.peel_refs().walk() {
if let GenericArgKind::Type(ty) = arg.kind()
&& let ty::Dynamic(data, _, _) = ty.kind()
&& let ty::Dynamic(data, _) = ty.kind()
{
// FIXME(arbitrary_self_types): This is likely broken for receivers which
// have a "non-self" trait objects as a generic argument.

View file

@ -614,7 +614,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let (maybe_null, drop_fn, fn_abi, drop_instance) = match ty.kind() {
// FIXME(eddyb) perhaps move some of this logic into
// `Instance::resolve_drop_in_place`?
ty::Dynamic(_, _, ty::Dyn) => {
ty::Dynamic(_, _) => {
// IN THIS ARM, WE HAVE:
// ty = *mut (dyn Trait)
// which is: exists<T> ( *mut T, Vtable<T: Trait> )

View file

@ -658,7 +658,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let val = self.read_immediate(&receiver)?;
break self.ref_to_mplace(&val)?;
}
ty::Dynamic(.., ty::Dyn) => break receiver.assert_mem_place(), // no immediate unsized values
ty::Dynamic(..) => break receiver.assert_mem_place(), // no immediate unsized values
_ => {
// Not there yet, search for the only non-ZST field.
// (The rules for `DispatchFromDyn` ensure there's exactly one such field.)
@ -675,7 +675,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// (For that reason we also cannot use `unpack_dyn_trait`.)
let receiver_tail =
self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.typing_env);
let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
let ty::Dynamic(receiver_trait, _) = receiver_tail.kind() else {
span_bug!(self.cur_span(), "dynamic call on non-`dyn` type {}", receiver_tail)
};
assert!(receiver_place.layout.is_unsized());
@ -822,7 +822,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// instead we do the virtual call stuff ourselves. It's easier here than in `eval_fn_call`
// since we can just get a place of the underlying type and use `mplace_to_ref`.
let place = match place.layout.ty.kind() {
ty::Dynamic(data, _, ty::Dyn) => {
ty::Dynamic(data, _) => {
// Dropping a trait object. Need to find actual drop fn.
self.unpack_dyn_trait(&place, data)?
}

View file

@ -386,7 +386,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
);
self.write_immediate(val, dest)
}
(ty::Dynamic(data_a, _, ty::Dyn), ty::Dynamic(data_b, _, ty::Dyn)) => {
(ty::Dynamic(data_a, _), ty::Dynamic(data_b, _)) => {
let val = self.read_immediate(src)?;
// MIR building generates odd NOP casts, prevent them from causing unexpected trouble.
// See <https://github.com/rust-lang/rust/issues/128880>.
@ -436,7 +436,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let new_vptr = self.get_vtable_ptr(ty, data_b)?;
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
}
(_, &ty::Dynamic(data, _, ty::Dyn)) => {
(_, &ty::Dynamic(data, _)) => {
// Initial cast from sized to dyn trait
let vtable = self.get_vtable_ptr(src_pointee_ty, data)?;
let ptr = self.read_pointer(src)?;

View file

@ -469,7 +469,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
interp_ok(Some((full_size, full_align)))
}
ty::Dynamic(expected_trait, _, ty::Dyn) => {
ty::Dynamic(expected_trait, _) => {
let vtable = metadata.unwrap_meta().to_pointer(self)?;
// Read size and align from vtable (already checks size).
interp_ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?))

View file

@ -181,7 +181,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)

View file

@ -509,7 +509,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
| ty::Never
| ty::Error(_) => true,
ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false,
ty::Str | ty::Slice(_) | ty::Dynamic(_, _) | ty::Foreign(..) => false,
ty::Tuple(tys) => tys.last().is_none_or(|ty| is_very_trivially_sized(*ty)),

View file

@ -109,7 +109,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
assert!(
matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _, ty::Dyn)),
matches!(mplace.layout.ty.kind(), ty::Dynamic(_, _)),
"`unpack_dyn_trait` only makes sense on `dyn*` types"
);
let vtable = mplace.meta().unwrap_meta().to_pointer(self)?;

View file

@ -449,7 +449,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
) -> InterpResult<'tcx> {
let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.typing_env);
match tail.kind() {
ty::Dynamic(data, _, ty::Dyn) => {
ty::Dynamic(data, _) => {
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
// Make sure it is a genuine vtable pointer for the right trait.
try_validation!(

View file

@ -90,7 +90,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
// Special treatment for special types, where the (static) layout is not sufficient.
match *ty.kind() {
// If it is a trait object, switch to the real type that was used to create it.
ty::Dynamic(data, _, ty::Dyn) => {
ty::Dynamic(data, _) => {
// Dyn types. This is unsized, and the actual dynamic type of the data is given by the
// vtable stored in the place metadata.
// unsized values are never immediate, so we can assert_mem_place

View file

@ -41,7 +41,7 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> {
| ty::FnPtr(..)
| ty::Never
| ty::Tuple(_)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::UnsafeBinder(_) => self.pretty_print_type(ty),
// Placeholders (all printed as `_` to uniformize them).

View file

@ -152,7 +152,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
);
continue;
};
let ty::Dynamic(data, _, _) = *ty.kind() else {
let ty::Dynamic(data, _) = *ty.kind() else {
tcx.dcx()
.span_err(attr.span(), "`rustc_dump_vtable` to type alias of dyn type");
continue;

View file

@ -1,16 +1,22 @@
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::struct_span_code_err;
use rustc_errors::{
Applicability, Diag, EmissionGuarantee, StashKey, Suggestions, struct_span_code_err,
};
use rustc_hir as hir;
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::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS};
use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan;
use rustc_middle::ty::{
self, BottomUpFolder, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
self, BottomUpFolder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
TypeVisitableExt, Upcast,
};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
use rustc_trait_selection::traits;
use smallvec::{SmallVec, smallvec};
use tracing::{debug, instrument};
@ -28,11 +34,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir_id: hir::HirId,
hir_bounds: &[hir::PolyTraitRef<'tcx>],
lifetime: &hir::Lifetime,
representation: DynKind,
syntax: TraitObjectSyntax,
) -> Ty<'tcx> {
let tcx = self.tcx();
let dummy_self = tcx.types.trait_object_dummy_self;
match syntax {
TraitObjectSyntax::Dyn => {}
TraitObjectSyntax::None => {
match self.prohibit_or_lint_bare_trait_object_ty(span, hir_id, hir_bounds) {
// Don't continue with type analysis if the `dyn` keyword is missing.
// It generates confusing errors, especially if the user meant to use
// another keyword like `impl`.
Some(guar) => return Ty::new_error(tcx, guar),
None => {}
}
}
}
let mut user_written_bounds = Vec::new();
let mut potential_assoc_types = Vec::new();
for poly_trait_ref in hir_bounds.iter() {
@ -47,10 +66,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
let ast_bounds: Vec<_> =
hir_bounds.iter().map(|&trait_ref| hir::GenericBound::Trait(trait_ref)).collect();
self.add_default_traits(&mut user_written_bounds, dummy_self, &ast_bounds, None, span);
self.add_default_traits(
&mut user_written_bounds,
dummy_self,
&hir_bounds
.iter()
.map(|&trait_ref| hir::GenericBound::Trait(trait_ref))
.collect::<Vec<_>>(),
None,
span,
);
let (elaborated_trait_bounds, elaborated_projection_bounds) =
traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
@ -431,7 +456,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};
debug!(?region_bound);
Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
Ty::new_dynamic(tcx, existential_predicates, region_bound)
}
/// Check that elaborating the principal of a trait ref doesn't lead to projections
@ -483,6 +508,521 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
},
);
}
/// Prohibit or lint against *bare* trait object types depending on the edition.
///
/// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`.
/// In edition 2021 and onward we emit a hard error for them.
fn prohibit_or_lint_bare_trait_object_ty(
&self,
span: Span,
hir_id: hir::HirId,
hir_bounds: &[hir::PolyTraitRef<'tcx>],
) -> Option<ErrorGuaranteed> {
let tcx = self.tcx();
let [poly_trait_ref, ..] = hir_bounds else { return None };
let in_path = match tcx.parent_hir_node(hir_id) {
hir::Node::Ty(hir::Ty {
kind: hir::TyKind::Path(hir::QPath::TypeRelative(qself, _)),
..
})
| hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
..
})
| hir::Node::PatExpr(hir::PatExpr {
kind: hir::PatExprKind::Path(hir::QPath::TypeRelative(qself, _)),
..
}) if qself.hir_id == hir_id => true,
_ => false,
};
let needs_bracket = in_path
&& !tcx
.sess
.source_map()
.span_to_prev_source(span)
.ok()
.is_some_and(|s| s.trim_end().ends_with('<'));
let is_global = poly_trait_ref.trait_ref.path.is_global();
let mut sugg = vec![(
span.shrink_to_lo(),
format!(
"{}dyn {}",
if needs_bracket { "<" } else { "" },
if is_global { "(" } else { "" },
),
)];
if is_global || needs_bracket {
sugg.push((
span.shrink_to_hi(),
format!(
"{}{}",
if is_global { ")" } else { "" },
if needs_bracket { ">" } else { "" },
),
));
}
if span.edition().at_least_rust_2021() {
let mut diag = rustc_errors::struct_span_code_err!(
self.dcx(),
span,
E0782,
"{}",
"expected a type, found a trait"
);
if span.can_be_used_for_suggestions()
&& poly_trait_ref.trait_ref.trait_def_id().is_some()
&& !self.maybe_suggest_impl_trait(span, hir_id, hir_bounds, &mut diag)
&& !self.maybe_suggest_dyn_trait(hir_id, sugg, &mut diag)
{
self.maybe_suggest_add_generic_impl_trait(span, hir_id, &mut diag);
}
// Check if the impl trait that we are considering is an impl of a local trait.
self.maybe_suggest_blanket_trait_impl(span, hir_id, &mut diag);
self.maybe_suggest_assoc_ty_bound(hir_id, &mut diag);
self.maybe_suggest_typoed_method(
hir_id,
poly_trait_ref.trait_ref.trait_def_id(),
&mut diag,
);
// In case there is an associated type with the same name
// Add the suggestion to this error
if let Some(mut sugg) =
self.dcx().steal_non_err(span, StashKey::AssociatedTypeSuggestion)
&& let Suggestions::Enabled(ref mut s1) = diag.suggestions
&& let Suggestions::Enabled(ref mut s2) = sugg.suggestions
{
s1.append(s2);
sugg.cancel();
}
Some(diag.emit())
} else {
tcx.node_span_lint(BARE_TRAIT_OBJECTS, hir_id, span, |lint| {
lint.primary_message("trait objects without an explicit `dyn` are deprecated");
if span.can_be_used_for_suggestions() {
lint.multipart_suggestion_verbose(
"if this is a dyn-compatible trait, use `dyn`",
sugg,
Applicability::MachineApplicable,
);
}
self.maybe_suggest_blanket_trait_impl(span, hir_id, lint);
});
None
}
}
/// For a struct or enum with an invalid bare trait object field, suggest turning
/// it into a generic type bound.
fn maybe_suggest_add_generic_impl_trait(
&self,
span: Span,
hir_id: hir::HirId,
diag: &mut Diag<'_>,
) -> bool {
let tcx = self.tcx();
let parent_hir_id = tcx.parent_hir_id(hir_id);
let parent_item = tcx.hir_get_parent_item(hir_id).def_id;
let generics = match tcx.hir_node_by_def_id(parent_item) {
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Struct(_, generics, variant),
..
}) => {
if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) {
return false;
}
generics
}
hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics, def), .. }) => {
if !def
.variants
.iter()
.flat_map(|variant| variant.data.fields().iter())
.any(|field| field.hir_id == parent_hir_id)
{
return false;
}
generics
}
_ => return false,
};
let Ok(rendered_ty) = tcx.sess.source_map().span_to_snippet(span) else {
return false;
};
let param = "TUV"
.chars()
.map(|c| c.to_string())
.chain((0..).map(|i| format!("P{i}")))
.find(|s| !generics.params.iter().any(|param| param.name.ident().as_str() == s))
.expect("we definitely can find at least one param name to generate");
let mut sugg = vec![(span, param.to_string())];
if let Some(insertion_span) = generics.span_for_param_suggestion() {
sugg.push((insertion_span, format!(", {param}: {}", rendered_ty)));
} else {
sugg.push((generics.where_clause_span, format!("<{param}: {}>", rendered_ty)));
}
diag.multipart_suggestion_verbose(
"you might be missing a type parameter",
sugg,
Applicability::MachineApplicable,
);
true
}
/// Make sure that we are in the condition to suggest the blanket implementation.
fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
&self,
span: Span,
hir_id: hir::HirId,
diag: &mut Diag<'_, G>,
) {
let tcx = self.tcx();
let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }),
..
}) = tcx.hir_node_by_def_id(parent_id)
&& hir_id == impl_self_ty.hir_id
{
let Some(of_trait) = of_trait else {
diag.span_suggestion_verbose(
impl_self_ty.span.shrink_to_hi(),
"you might have intended to implement this trait for a given type",
format!(" for /* Type */"),
Applicability::HasPlaceholders,
);
return;
};
if !of_trait.trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
return;
}
let of_trait_span = of_trait.trait_ref.path.span;
// make sure that we are not calling unwrap to abort during the compilation
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
return;
};
let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(span) else {
return;
};
let sugg = self.add_generic_param_suggestion(generics, span, &impl_trait_name);
diag.multipart_suggestion(
format!(
"alternatively use a blanket implementation to implement `{of_trait_name}` for \
all types that also implement `{impl_trait_name}`"
),
sugg,
Applicability::MaybeIncorrect,
);
}
}
/// Try our best to approximate when adding `dyn` would be helpful for a bare
/// trait object.
///
/// Right now, this is if the type is either directly nested in another ty,
/// or if it's in the tail field within a struct. This approximates what the
/// user would've gotten on edition 2015, except for the case where we have
/// an *obvious* knock-on `Sized` error.
fn maybe_suggest_dyn_trait(
&self,
hir_id: hir::HirId,
sugg: Vec<(Span, String)>,
diag: &mut Diag<'_>,
) -> bool {
let tcx = self.tcx();
// Look at the direct HIR parent, since we care about the relationship between
// the type and the thing that directly encloses it.
match tcx.parent_hir_node(hir_id) {
// These are all generally ok. Namely, when a trait object is nested
// into another expression or ty, it's either very certain that they
// missed the ty (e.g. `&Trait`) or it's not really possible to tell
// what their intention is, so let's not give confusing suggestions and
// just mention `dyn`. The user can make up their mind what to do here.
hir::Node::Ty(_)
| hir::Node::Expr(_)
| hir::Node::PatExpr(_)
| hir::Node::PathSegment(_)
| hir::Node::AssocItemConstraint(_)
| hir::Node::TraitRef(_)
| hir::Node::Item(_)
| hir::Node::WherePredicate(_) => {}
hir::Node::Field(field) => {
// Enums can't have unsized fields, fields can only have an unsized tail field.
if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Struct(_, _, variant), ..
}) = tcx.parent_hir_node(field.hir_id)
&& variant
.fields()
.last()
.is_some_and(|tail_field| tail_field.hir_id == field.hir_id)
{
// Ok
} else {
return false;
}
}
_ => return false,
}
// FIXME: Only emit this suggestion if the trait is dyn-compatible.
diag.multipart_suggestion_verbose(
"you can add the `dyn` keyword if you want a trait object",
sugg,
Applicability::MachineApplicable,
);
true
}
fn add_generic_param_suggestion(
&self,
generics: &hir::Generics<'_>,
self_ty_span: Span,
impl_trait_name: &str,
) -> Vec<(Span, String)> {
// check if the trait has generics, to make a correct suggestion
let param_name = generics.params.next_type_param_name(None);
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
(span, format!(", {param_name}: {impl_trait_name}"))
} else {
(generics.span, format!("<{param_name}: {impl_trait_name}>"))
};
vec![(self_ty_span, param_name), add_generic_sugg]
}
/// Make sure that we are in the condition to suggest `impl Trait`.
fn maybe_suggest_impl_trait(
&self,
span: Span,
hir_id: hir::HirId,
hir_bounds: &[hir::PolyTraitRef<'tcx>],
diag: &mut Diag<'_>,
) -> bool {
let tcx = self.tcx();
let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
// FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
// and suggest `Trait0<Ty = impl Trait1>`.
// Functions are found in three different contexts.
// 1. Independent functions
// 2. Functions inside trait blocks
// 3. Functions inside impl blocks
let (sig, generics) = match tcx.hir_node_by_def_id(parent_id) {
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn { sig, generics, .. }, ..
}) => (sig, generics),
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(sig, _),
generics,
..
}) => (sig, generics),
hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(sig, _),
generics,
..
}) => (sig, generics),
_ => return false,
};
let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(span) else {
return false;
};
let impl_sugg = vec![(span.shrink_to_lo(), "impl ".to_string())];
// Check if trait object is safe for suggesting dynamic dispatch.
let is_dyn_compatible = hir_bounds.iter().all(|bound| match bound.trait_ref.path.res {
Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id),
_ => false,
});
let borrowed = matches!(
tcx.parent_hir_node(hir_id),
hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. })
);
// Suggestions for function return type.
if let hir::FnRetTy::Return(ty) = sig.decl.output
&& ty.peel_refs().hir_id == hir_id
{
let pre = if !is_dyn_compatible {
format!("`{trait_name}` is dyn-incompatible, ")
} else {
String::new()
};
let msg = format!(
"{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
single underlying type",
);
diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
// Suggest `Box<dyn Trait>` for return type
if is_dyn_compatible {
// If the return type is `&Trait`, we don't want
// the ampersand to be displayed in the `Box<dyn Trait>`
// suggestion.
let suggestion = if borrowed {
vec![(ty.span, format!("Box<dyn {trait_name}>"))]
} else {
vec![
(ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
(ty.span.shrink_to_hi(), ">".to_string()),
]
};
diag.multipart_suggestion_verbose(
"alternatively, you can return an owned trait object",
suggestion,
Applicability::MachineApplicable,
);
}
return true;
}
// Suggestions for function parameters.
for ty in sig.decl.inputs {
if ty.peel_refs().hir_id != hir_id {
continue;
}
let sugg = self.add_generic_param_suggestion(generics, span, &trait_name);
diag.multipart_suggestion_verbose(
format!("use a new generic type parameter, constrained by `{trait_name}`"),
sugg,
Applicability::MachineApplicable,
);
diag.multipart_suggestion_verbose(
"you can also use an opaque type, but users won't be able to specify the type \
parameter when calling the `fn`, having to rely exclusively on type inference",
impl_sugg,
Applicability::MachineApplicable,
);
if !is_dyn_compatible {
diag.note(format!(
"`{trait_name}` is dyn-incompatible, otherwise a trait object could be used"
));
} else {
// No ampersand in suggestion if it's borrowed already
let (dyn_str, paren_dyn_str) =
if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
let sugg = if let [_, _, ..] = hir_bounds {
// There is more than one trait bound, we need surrounding parentheses.
vec![
(span.shrink_to_lo(), paren_dyn_str.to_string()),
(span.shrink_to_hi(), ")".to_string()),
]
} else {
vec![(span.shrink_to_lo(), dyn_str.to_string())]
};
diag.multipart_suggestion_verbose(
format!(
"alternatively, use a trait object to accept any type that implements \
`{trait_name}`, accessing its methods at runtime using dynamic dispatch",
),
sugg,
Applicability::MachineApplicable,
);
}
return true;
}
false
}
fn maybe_suggest_assoc_ty_bound(&self, hir_id: hir::HirId, diag: &mut Diag<'_>) {
let mut parents = self.tcx().hir_parent_iter(hir_id);
if let Some((c_hir_id, hir::Node::AssocItemConstraint(constraint))) = parents.next()
&& let Some(obj_ty) = constraint.ty()
&& let Some((_, hir::Node::TraitRef(trait_ref))) = parents.next()
{
if let Some((_, hir::Node::Ty(ty))) = parents.next()
&& let hir::TyKind::TraitObject(..) = ty.kind
{
// Assoc ty bounds aren't permitted inside trait object types.
return;
}
if trait_ref
.path
.segments
.iter()
.find_map(|seg| {
seg.args.filter(|args| args.constraints.iter().any(|c| c.hir_id == c_hir_id))
})
.is_none_or(|args| args.parenthesized != hir::GenericArgsParentheses::No)
{
// Only consider angle-bracketed args (where we have a `=` to replace with `:`).
return;
}
let lo = if constraint.gen_args.span_ext.is_dummy() {
constraint.ident.span
} else {
constraint.gen_args.span_ext
};
let hi = obj_ty.span;
if !lo.eq_ctxt(hi) {
return;
}
diag.span_suggestion_verbose(
lo.between(hi),
"you might have meant to write a bound here",
": ",
Applicability::MaybeIncorrect,
);
}
}
fn maybe_suggest_typoed_method(
&self,
hir_id: hir::HirId,
trait_def_id: Option<DefId>,
diag: &mut Diag<'_>,
) {
let tcx = self.tcx();
let Some(trait_def_id) = trait_def_id else {
return;
};
let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Path(hir::QPath::TypeRelative(path_ty, segment)),
..
}) = tcx.parent_hir_node(hir_id)
else {
return;
};
if path_ty.hir_id != hir_id {
return;
}
let names: Vec<_> = tcx
.associated_items(trait_def_id)
.in_definition_order()
.filter(|assoc| assoc.namespace() == hir::def::Namespace::ValueNS)
.map(|cand| cand.name())
.collect();
if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
diag.span_suggestion_verbose(
segment.ident.span,
format!(
"you may have misspelled this associated item, causing `{}` \
to be interpreted as a type rather than a trait",
tcx.item_name(trait_def_id),
),
typo,
Applicability::MaybeIncorrect,
);
}
}
}
fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(

View file

@ -859,7 +859,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
}
// Point at the trait object that couldn't satisfy the bound.
ty::Dynamic(preds, _, _) => {
ty::Dynamic(preds, _) => {
for pred in preds.iter() {
match pred.skip_binder() {
ty::ExistentialPredicate::Trait(tr) => {

View file

@ -1,533 +0,0 @@
use rustc_ast::TraitObjectSyntax;
use rustc_errors::codes::*;
use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, StashKey, Suggestions};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace, Res};
use rustc_hir::def_id::DefId;
use rustc_lint_defs::Applicability;
use rustc_lint_defs::builtin::BARE_TRAIT_OBJECTS;
use rustc_span::Span;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
use super::HirTyLowerer;
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// Prohibit or lint against *bare* trait object types depending on the edition.
///
/// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`.
/// In edition 2021 and onward we emit a hard error for them.
pub(super) fn prohibit_or_lint_bare_trait_object_ty(
&self,
self_ty: &hir::Ty<'_>,
) -> Option<ErrorGuaranteed> {
let tcx = self.tcx();
let poly_trait_ref = if let hir::TyKind::TraitObject([poly_trait_ref, ..], tagged_ptr) =
self_ty.kind
&& let TraitObjectSyntax::None = tagged_ptr.tag()
{
poly_trait_ref
} else {
return None;
};
let in_path = match tcx.parent_hir_node(self_ty.hir_id) {
hir::Node::Ty(hir::Ty {
kind: hir::TyKind::Path(hir::QPath::TypeRelative(qself, _)),
..
})
| hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
..
})
| hir::Node::PatExpr(hir::PatExpr {
kind: hir::PatExprKind::Path(hir::QPath::TypeRelative(qself, _)),
..
}) if qself.hir_id == self_ty.hir_id => true,
_ => false,
};
let needs_bracket = in_path
&& !tcx
.sess
.source_map()
.span_to_prev_source(self_ty.span)
.ok()
.is_some_and(|s| s.trim_end().ends_with('<'));
let is_global = poly_trait_ref.trait_ref.path.is_global();
let mut sugg = vec![(
self_ty.span.shrink_to_lo(),
format!(
"{}dyn {}",
if needs_bracket { "<" } else { "" },
if is_global { "(" } else { "" },
),
)];
if is_global || needs_bracket {
sugg.push((
self_ty.span.shrink_to_hi(),
format!(
"{}{}",
if is_global { ")" } else { "" },
if needs_bracket { ">" } else { "" },
),
));
}
if self_ty.span.edition().at_least_rust_2021() {
let mut diag = rustc_errors::struct_span_code_err!(
self.dcx(),
self_ty.span,
E0782,
"{}",
"expected a type, found a trait"
);
if self_ty.span.can_be_used_for_suggestions()
&& poly_trait_ref.trait_ref.trait_def_id().is_some()
&& !self.maybe_suggest_impl_trait(self_ty, &mut diag)
&& !self.maybe_suggest_dyn_trait(self_ty, sugg, &mut diag)
{
self.maybe_suggest_add_generic_impl_trait(self_ty, &mut diag);
}
// Check if the impl trait that we are considering is an impl of a local trait.
self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag);
self.maybe_suggest_assoc_ty_bound(self_ty, &mut diag);
self.maybe_suggest_typoed_method(
self_ty,
poly_trait_ref.trait_ref.trait_def_id(),
&mut diag,
);
// In case there is an associated type with the same name
// Add the suggestion to this error
if let Some(mut sugg) =
self.dcx().steal_non_err(self_ty.span, StashKey::AssociatedTypeSuggestion)
&& let Suggestions::Enabled(ref mut s1) = diag.suggestions
&& let Suggestions::Enabled(ref mut s2) = sugg.suggestions
{
s1.append(s2);
sugg.cancel();
}
Some(diag.emit())
} else {
tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, |lint| {
lint.primary_message("trait objects without an explicit `dyn` are deprecated");
if self_ty.span.can_be_used_for_suggestions() {
lint.multipart_suggestion_verbose(
"if this is a dyn-compatible trait, use `dyn`",
sugg,
Applicability::MachineApplicable,
);
}
self.maybe_suggest_blanket_trait_impl(self_ty, lint);
});
None
}
}
/// For a struct or enum with an invalid bare trait object field, suggest turning
/// it into a generic type bound.
fn maybe_suggest_add_generic_impl_trait(
&self,
self_ty: &hir::Ty<'_>,
diag: &mut Diag<'_>,
) -> bool {
let tcx = self.tcx();
let parent_hir_id = tcx.parent_hir_id(self_ty.hir_id);
let parent_item = tcx.hir_get_parent_item(self_ty.hir_id).def_id;
let generics = match tcx.hir_node_by_def_id(parent_item) {
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Struct(_, generics, variant),
..
}) => {
if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) {
return false;
}
generics
}
hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(_, generics, def), .. }) => {
if !def
.variants
.iter()
.flat_map(|variant| variant.data.fields().iter())
.any(|field| field.hir_id == parent_hir_id)
{
return false;
}
generics
}
_ => return false,
};
let Ok(rendered_ty) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
return false;
};
let param = "TUV"
.chars()
.map(|c| c.to_string())
.chain((0..).map(|i| format!("P{i}")))
.find(|s| !generics.params.iter().any(|param| param.name.ident().as_str() == s))
.expect("we definitely can find at least one param name to generate");
let mut sugg = vec![(self_ty.span, param.to_string())];
if let Some(insertion_span) = generics.span_for_param_suggestion() {
sugg.push((insertion_span, format!(", {param}: {}", rendered_ty)));
} else {
sugg.push((generics.where_clause_span, format!("<{param}: {}>", rendered_ty)));
}
diag.multipart_suggestion_verbose(
"you might be missing a type parameter",
sugg,
Applicability::MachineApplicable,
);
true
}
/// Make sure that we are in the condition to suggest the blanket implementation.
fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
&self,
self_ty: &hir::Ty<'_>,
diag: &mut Diag<'_, G>,
) {
let tcx = self.tcx();
let parent_id = tcx.hir_get_parent_item(self_ty.hir_id).def_id;
if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, of_trait, generics, .. }),
..
}) = tcx.hir_node_by_def_id(parent_id)
&& self_ty.hir_id == impl_self_ty.hir_id
{
let Some(of_trait) = of_trait else {
diag.span_suggestion_verbose(
impl_self_ty.span.shrink_to_hi(),
"you might have intended to implement this trait for a given type",
format!(" for /* Type */"),
Applicability::HasPlaceholders,
);
return;
};
if !of_trait.trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
return;
}
let of_trait_span = of_trait.trait_ref.path.span;
// make sure that we are not calling unwrap to abort during the compilation
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
return;
};
let Ok(impl_trait_name) = self.tcx().sess.source_map().span_to_snippet(self_ty.span)
else {
return;
};
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name);
diag.multipart_suggestion(
format!(
"alternatively use a blanket implementation to implement `{of_trait_name}` for \
all types that also implement `{impl_trait_name}`"
),
sugg,
Applicability::MaybeIncorrect,
);
}
}
/// Try our best to approximate when adding `dyn` would be helpful for a bare
/// trait object.
///
/// Right now, this is if the type is either directly nested in another ty,
/// or if it's in the tail field within a struct. This approximates what the
/// user would've gotten on edition 2015, except for the case where we have
/// an *obvious* knock-on `Sized` error.
fn maybe_suggest_dyn_trait(
&self,
self_ty: &hir::Ty<'_>,
sugg: Vec<(Span, String)>,
diag: &mut Diag<'_>,
) -> bool {
let tcx = self.tcx();
// Look at the direct HIR parent, since we care about the relationship between
// the type and the thing that directly encloses it.
match tcx.parent_hir_node(self_ty.hir_id) {
// These are all generally ok. Namely, when a trait object is nested
// into another expression or ty, it's either very certain that they
// missed the ty (e.g. `&Trait`) or it's not really possible to tell
// what their intention is, so let's not give confusing suggestions and
// just mention `dyn`. The user can make up their mind what to do here.
hir::Node::Ty(_)
| hir::Node::Expr(_)
| hir::Node::PatExpr(_)
| hir::Node::PathSegment(_)
| hir::Node::AssocItemConstraint(_)
| hir::Node::TraitRef(_)
| hir::Node::Item(_)
| hir::Node::WherePredicate(_) => {}
hir::Node::Field(field) => {
// Enums can't have unsized fields, fields can only have an unsized tail field.
if let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Struct(_, _, variant), ..
}) = tcx.parent_hir_node(field.hir_id)
&& variant
.fields()
.last()
.is_some_and(|tail_field| tail_field.hir_id == field.hir_id)
{
// Ok
} else {
return false;
}
}
_ => return false,
}
// FIXME: Only emit this suggestion if the trait is dyn-compatible.
diag.multipart_suggestion_verbose(
"you can add the `dyn` keyword if you want a trait object",
sugg,
Applicability::MachineApplicable,
);
true
}
fn add_generic_param_suggestion(
&self,
generics: &hir::Generics<'_>,
self_ty_span: Span,
impl_trait_name: &str,
) -> Vec<(Span, String)> {
// check if the trait has generics, to make a correct suggestion
let param_name = generics.params.next_type_param_name(None);
let add_generic_sugg = if let Some(span) = generics.span_for_param_suggestion() {
(span, format!(", {param_name}: {impl_trait_name}"))
} else {
(generics.span, format!("<{param_name}: {impl_trait_name}>"))
};
vec![(self_ty_span, param_name), add_generic_sugg]
}
/// Make sure that we are in the condition to suggest `impl Trait`.
fn maybe_suggest_impl_trait(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) -> bool {
let tcx = self.tcx();
let parent_id = tcx.hir_get_parent_item(self_ty.hir_id).def_id;
// FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
// and suggest `Trait0<Ty = impl Trait1>`.
// Functions are found in three different contexts.
// 1. Independent functions
// 2. Functions inside trait blocks
// 3. Functions inside impl blocks
let (sig, generics) = match tcx.hir_node_by_def_id(parent_id) {
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn { sig, generics, .. }, ..
}) => (sig, generics),
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(sig, _),
generics,
..
}) => (sig, generics),
hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(sig, _),
generics,
..
}) => (sig, generics),
_ => return false,
};
let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
return false;
};
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
// Check if trait object is safe for suggesting dynamic dispatch.
let is_dyn_compatible = match self_ty.kind {
hir::TyKind::TraitObject(objects, ..) => {
objects.iter().all(|o| match o.trait_ref.path.res {
Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id),
_ => false,
})
}
_ => false,
};
let borrowed = matches!(
tcx.parent_hir_node(self_ty.hir_id),
hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. })
);
// Suggestions for function return type.
if let hir::FnRetTy::Return(ty) = sig.decl.output
&& ty.peel_refs().hir_id == self_ty.hir_id
{
let pre = if !is_dyn_compatible {
format!("`{trait_name}` is dyn-incompatible, ")
} else {
String::new()
};
let msg = format!(
"{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
single underlying type",
);
diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
// Suggest `Box<dyn Trait>` for return type
if is_dyn_compatible {
// If the return type is `&Trait`, we don't want
// the ampersand to be displayed in the `Box<dyn Trait>`
// suggestion.
let suggestion = if borrowed {
vec![(ty.span, format!("Box<dyn {trait_name}>"))]
} else {
vec![
(ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
(ty.span.shrink_to_hi(), ">".to_string()),
]
};
diag.multipart_suggestion_verbose(
"alternatively, you can return an owned trait object",
suggestion,
Applicability::MachineApplicable,
);
}
return true;
}
// Suggestions for function parameters.
for ty in sig.decl.inputs {
if ty.peel_refs().hir_id != self_ty.hir_id {
continue;
}
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name);
diag.multipart_suggestion_verbose(
format!("use a new generic type parameter, constrained by `{trait_name}`"),
sugg,
Applicability::MachineApplicable,
);
diag.multipart_suggestion_verbose(
"you can also use an opaque type, but users won't be able to specify the type \
parameter when calling the `fn`, having to rely exclusively on type inference",
impl_sugg,
Applicability::MachineApplicable,
);
if !is_dyn_compatible {
diag.note(format!(
"`{trait_name}` is dyn-incompatible, otherwise a trait object could be used"
));
} else {
// No ampersand in suggestion if it's borrowed already
let (dyn_str, paren_dyn_str) =
if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _) = self_ty.kind {
// There is more than one trait bound, we need surrounding parentheses.
vec![
(self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()),
(self_ty.span.shrink_to_hi(), ")".to_string()),
]
} else {
vec![(self_ty.span.shrink_to_lo(), dyn_str.to_string())]
};
diag.multipart_suggestion_verbose(
format!(
"alternatively, use a trait object to accept any type that implements \
`{trait_name}`, accessing its methods at runtime using dynamic dispatch",
),
sugg,
Applicability::MachineApplicable,
);
}
return true;
}
false
}
fn maybe_suggest_assoc_ty_bound(&self, self_ty: &hir::Ty<'_>, diag: &mut Diag<'_>) {
let mut parents = self.tcx().hir_parent_iter(self_ty.hir_id);
if let Some((c_hir_id, hir::Node::AssocItemConstraint(constraint))) = parents.next()
&& let Some(obj_ty) = constraint.ty()
&& let Some((_, hir::Node::TraitRef(trait_ref))) = parents.next()
{
if let Some((_, hir::Node::Ty(ty))) = parents.next()
&& let hir::TyKind::TraitObject(..) = ty.kind
{
// Assoc ty bounds aren't permitted inside trait object types.
return;
}
if trait_ref
.path
.segments
.iter()
.find_map(|seg| {
seg.args.filter(|args| args.constraints.iter().any(|c| c.hir_id == c_hir_id))
})
.is_none_or(|args| args.parenthesized != hir::GenericArgsParentheses::No)
{
// Only consider angle-bracketed args (where we have a `=` to replace with `:`).
return;
}
let lo = if constraint.gen_args.span_ext.is_dummy() {
constraint.ident.span
} else {
constraint.gen_args.span_ext
};
let hi = obj_ty.span;
if !lo.eq_ctxt(hi) {
return;
}
diag.span_suggestion_verbose(
lo.between(hi),
"you might have meant to write a bound here",
": ",
Applicability::MaybeIncorrect,
);
}
}
fn maybe_suggest_typoed_method(
&self,
self_ty: &hir::Ty<'_>,
trait_def_id: Option<DefId>,
diag: &mut Diag<'_>,
) {
let tcx = self.tcx();
let Some(trait_def_id) = trait_def_id else {
return;
};
let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Path(hir::QPath::TypeRelative(path_ty, segment)),
..
}) = tcx.parent_hir_node(self_ty.hir_id)
else {
return;
};
if path_ty.hir_id != self_ty.hir_id {
return;
}
let names: Vec<_> = tcx
.associated_items(trait_def_id)
.in_definition_order()
.filter(|assoc| assoc.namespace() == Namespace::ValueNS)
.map(|cand| cand.name())
.collect();
if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
diag.span_suggestion_verbose(
segment.ident.span,
format!(
"you may have misspelled this associated item, causing `{}` \
to be interpreted as a type rather than a trait",
tcx.item_name(trait_def_id),
),
typo,
Applicability::MaybeIncorrect,
);
}
}
}

View file

@ -15,15 +15,13 @@
mod bounds;
mod cmse;
mod dyn_compatibility;
mod dyn_trait;
pub mod errors;
pub mod generics;
mod lint;
use std::assert_matches::assert_matches;
use std::slice;
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::{
@ -2428,19 +2426,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
),
hir::TyKind::TraitObject(bounds, tagged_ptr) => {
let lifetime = tagged_ptr.pointer();
let repr = tagged_ptr.tag();
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
// Don't continue with type analysis if the `dyn` keyword is missing
// It generates confusing errors, especially if the user meant to use another
// keyword like `impl`
Ty::new_error(tcx, guar)
} else {
let repr = match repr {
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
};
self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr)
}
let syntax = tagged_ptr.tag();
self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, syntax)
}
// If we encounter a fully qualified path with RTN generics, then it must have
// *not* gone through `lower_ty_maybe_return_type_notation`, and therefore

View file

@ -281,7 +281,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
self.add_constraints_from_args(current, data.def_id, data.args, variance);
}
ty::Dynamic(data, r, _) => {
ty::Dynamic(data, r) => {
// The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
self.add_constraints_from_region(current, r, variance);

View file

@ -103,7 +103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ok(match *t.kind() {
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty)),
ty::Dynamic(tty, _) => Some(PointerKind::VTable(tty)),
ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
None => Some(PointerKind::Thin),
Some(f) => {
@ -250,9 +250,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
// cases now. We do a more thorough check at the end, once
// inference is more completely known.
match cast_ty.kind() {
ty::Dynamic(_, _, ty::Dyn) | ty::Slice(..) => {
Err(check.report_cast_to_unsized_type(fcx))
}
ty::Dynamic(_, _) | ty::Slice(..) => Err(check.report_cast_to_unsized_type(fcx)),
_ => Ok(check),
}
}
@ -900,7 +898,6 @@ impl<'a, 'tcx> CastCheck<'tcx> {
&src_tty.without_auto_traits().collect::<Vec<_>>(),
),
tcx.lifetimes.re_erased,
ty::Dyn,
);
let dst_obj = Ty::new_dynamic(
tcx,
@ -908,7 +905,6 @@ impl<'a, 'tcx> CastCheck<'tcx> {
&dst_tty.without_auto_traits().collect::<Vec<_>>(),
),
tcx.lifetimes.re_erased,
ty::Dyn,
);
// `dyn Src = dyn Dst`, this checks for matching traits/generics/projections

View file

@ -558,7 +558,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(_, _)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)

View file

@ -1008,7 +1008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)
}
// Point at the trait object that couldn't satisfy the bound.
ty::Dynamic(preds, _, _) => {
ty::Dynamic(preds, _) => {
for pred in preds.iter() {
match pred.skip_binder() {
ty::ExistentialPredicate::Trait(tr) => {

View file

@ -66,11 +66,11 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
&& tcx.is_lang_item(did, LangItem::Deref)
// the self type is `dyn t_principal`
&& let self_ty = tcx.type_of(item.owner_id).instantiate_identity()
&& let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind()
&& let ty::Dynamic(data, _) = self_ty.kind()
&& let Some(self_principal) = data.principal()
// `<T as Deref>::Target` is `dyn target_principal`
&& let Some(target) = cx.get_associated_type(self_ty, did, sym::Target)
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
&& let ty::Dynamic(data, _) = target.kind()
&& let Some(target_principal) = data.principal()
// `target_principal` is a supertrait of `t_principal`
&& let Some(supertrait_principal) = supertraits(tcx, self_principal.with_self_ty(tcx, self_ty))

View file

@ -320,7 +320,7 @@ fn lint_wide_pointer<'tcx>(
};
(!ty.is_sized(cx.tcx, cx.typing_env()))
.then(|| (refs, modifiers, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn))))
.then(|| (refs, modifiers, matches!(ty.kind(), ty::Dynamic(_, _))))
};
// the left and right operands can have references, remove any explicit references

View file

@ -312,7 +312,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
})
.map(|inner| MustUsePath::Opaque(Box::new(inner)))
}
ty::Dynamic(binders, _, _) => binders.iter().find_map(|predicate| {
ty::Dynamic(binders, _) => binders.iter().find_map(|predicate| {
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
{
let def_id = trait_ref.def_id;

View file

@ -574,7 +574,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(_, _)

View file

@ -812,7 +812,7 @@ where
| ty::CoroutineWitness(..)
| ty::Foreign(..)
| ty::Pat(_, _)
| ty::Dynamic(_, _, ty::Dyn) => {
| ty::Dynamic(_, _) => {
bug!("TyAndLayout::field({:?}): not applicable", this)
}
@ -878,7 +878,7 @@ where
// `std::mem::uninitialized::<&dyn Trait>()`, for example.
if let ty::Adt(def, args) = metadata.kind()
&& tcx.is_lang_item(def.did(), LangItem::DynMetadata)
&& let ty::Dynamic(data, _, ty::Dyn) = args.type_at(0).kind()
&& let ty::Dynamic(data, _) = args.type_at(0).kind()
{
mk_dyn_vtable(data.principal())
} else {
@ -887,7 +887,7 @@ where
} else {
match tcx.struct_tail_for_codegen(pointee, cx.typing_env()).kind() {
ty::Slice(_) | ty::Str => tcx.types.usize,
ty::Dynamic(data, _, ty::Dyn) => mk_dyn_vtable(data.principal()),
ty::Dynamic(data, _) => mk_dyn_vtable(data.principal()),
_ => bug!("TyAndLayout::field({:?}): not applicable", this),
}
};

View file

@ -784,14 +784,12 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
},
},
ty::Adt(def, args) => self.print_def_path(def.did(), args)?,
ty::Dynamic(data, r, repr) => {
ty::Dynamic(data, r) => {
let print_r = self.should_print_optional_region(r);
if print_r {
write!(self, "(")?;
}
match repr {
ty::Dyn => write!(self, "dyn ")?,
}
write!(self, "dyn ")?;
data.print(self)?;
if print_r {
write!(self, " + ")?;

View file

@ -132,7 +132,7 @@ pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
| ty::Ref(_, _, _)
| ty::FnPtr(_, _)
| ty::Tuple(_)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Alias(_, _)
| ty::Bound(_, _)
| ty::Pat(_, _)

View file

@ -390,11 +390,9 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
ty::Array(typ, sz) => ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?),
ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?),
ty::Adt(tid, args) => ty::Adt(tid, args.try_fold_with(folder)?),
ty::Dynamic(trait_ty, region, representation) => ty::Dynamic(
trait_ty.try_fold_with(folder)?,
region.try_fold_with(folder)?,
representation,
),
ty::Dynamic(trait_ty, region) => {
ty::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?)
}
ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?),
ty::FnDef(def_id, args) => ty::FnDef(def_id, args.try_fold_with(folder)?),
ty::FnPtr(sig_tys, hdr) => ty::FnPtr(sig_tys.try_fold_with(folder)?, hdr),
@ -437,8 +435,8 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)),
ty::Slice(typ) => ty::Slice(typ.fold_with(folder)),
ty::Adt(tid, args) => ty::Adt(tid, args.fold_with(folder)),
ty::Dynamic(trait_ty, region, representation) => {
ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder), representation)
ty::Dynamic(trait_ty, region) => {
ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder))
}
ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)),
ty::FnDef(def_id, args) => ty::FnDef(def_id, args.fold_with(folder)),
@ -481,7 +479,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
}
ty::Slice(typ) => typ.visit_with(visitor),
ty::Adt(_, args) => args.visit_with(visitor),
ty::Dynamic(trait_ty, reg, _) => {
ty::Dynamic(trait_ty, reg) => {
try_visit!(trait_ty.visit_with(visitor));
reg.visit_with(visitor)
}

View file

@ -17,7 +17,7 @@ use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use rustc_type_ir::TyKind::*;
use rustc_type_ir::solve::SizedTraitKind;
use rustc_type_ir::walk::TypeWalker;
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate};
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, TypeVisitableExt, elaborate};
use tracing::instrument;
use ty::util::IntTypeExt;
@ -734,7 +734,6 @@ impl<'tcx> Ty<'tcx> {
tcx: TyCtxt<'tcx>,
obj: &'tcx List<ty::PolyExistentialPredicate<'tcx>>,
reg: ty::Region<'tcx>,
repr: DynKind,
) -> Ty<'tcx> {
if cfg!(debug_assertions) {
let projection_count = obj
@ -767,7 +766,7 @@ impl<'tcx> Ty<'tcx> {
but it has {projection_count}"
);
}
Ty::new(tcx, Dynamic(obj, reg, repr))
Ty::new(tcx, Dynamic(obj, reg))
}
#[inline]
@ -980,9 +979,8 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
interner: TyCtxt<'tcx>,
preds: &'tcx List<ty::PolyExistentialPredicate<'tcx>>,
region: ty::Region<'tcx>,
kind: ty::DynKind,
) -> Self {
Ty::new_dynamic(interner, preds, region, kind)
Ty::new_dynamic(interner, preds, region)
}
fn new_coroutine(
@ -1356,7 +1354,7 @@ impl<'tcx> Ty<'tcx> {
#[inline]
pub fn is_trait(self) -> bool {
matches!(self.kind(), Dynamic(_, _, ty::Dyn))
matches!(self.kind(), Dynamic(_, _))
}
#[inline]
@ -1671,7 +1669,7 @@ impl<'tcx> Ty<'tcx> {
ty::Str | ty::Slice(_) => Ok(tcx.types.usize),
ty::Dynamic(_, _, ty::Dyn) => {
ty::Dynamic(_, _) => {
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, DUMMY_SP);
Ok(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]))
}
@ -1853,7 +1851,7 @@ impl<'tcx> Ty<'tcx> {
| ty::Never
| ty::Error(_) => true,
ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) => match sizedness {
ty::Str | ty::Slice(_) | ty::Dynamic(_, _) => match sizedness {
SizedTraitKind::Sized => false,
SizedTraitKind::MetaSized => true,
},

View file

@ -152,7 +152,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(_, _)
@ -196,7 +196,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::CoroutineWitness(..)
| ty::Never
| ty::UnsafeBinder(_)

View file

@ -1884,7 +1884,7 @@ fn check_must_not_suspend_ty<'tcx>(
}
has_emitted
}
ty::Dynamic(binder, _, _) => {
ty::Dynamic(binder, _) => {
let mut has_emitted = false;
for predicate in binder.iter() {
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {

View file

@ -390,7 +390,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::UnsafeBinder(_)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(_, _)

View file

@ -86,7 +86,7 @@ where
) -> Result<Candidate<I>, NoSolution> {
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
let cx = ecx.cx();
let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else {
let ty::Dynamic(bounds, _) = goal.predicate.self_ty().kind() else {
panic!("expected object type in `probe_and_consider_object_bound_candidate`");
};
match structural_traits::predicates_for_object_candidate(

View file

@ -383,7 +383,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<I: Intern
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(..)
| ty::Never
@ -557,7 +557,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I:
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(..)
| ty::Never
@ -706,7 +706,7 @@ pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>(
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(..)
| ty::Never

View file

@ -665,7 +665,7 @@ where
ty::Str | ty::Slice(_) => Ty::new_usize(cx),
ty::Dynamic(_, _, ty::Dyn) => {
ty::Dynamic(_, _) => {
let dyn_metadata = cx.require_lang_item(SolverLangItem::DynMetadata);
cx.type_of(dyn_metadata)
.instantiate(cx, &[I::GenericArg::from(goal.predicate.self_ty())])
@ -916,7 +916,7 @@ where
| ty::Adt(_, _)
| ty::Str
| ty::Slice(_)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Tuple(_)
| ty::Error(_) => self_ty.discriminant_ty(ecx.cx()),

View file

@ -817,15 +817,13 @@ where
}
// Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`.
(
ty::Dynamic(a_data, a_region, ty::Dyn),
ty::Dynamic(b_data, b_region, ty::Dyn),
) => ecx.consider_builtin_dyn_upcast_candidates(
goal, a_data, a_region, b_data, b_region,
),
(ty::Dynamic(a_data, a_region), ty::Dynamic(b_data, b_region)) => ecx
.consider_builtin_dyn_upcast_candidates(
goal, a_data, a_region, b_data, b_region,
),
// `T` -> `dyn Trait` unsizing.
(_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
(_, ty::Dynamic(b_region, b_data)) => result_to_single(
ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
),

View file

@ -295,7 +295,7 @@ impl<'tcx, 'a> TypeVisitor<TyCtxt<'tcx>> for ExportableItemsChecker<'tcx, 'a> {
| ty::Ref(_, _, _)
| ty::Param(_)
| ty::Closure(_, _)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Coroutine(_, _)
| ty::Foreign(_)
| ty::Str

View file

@ -407,7 +407,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::Pat(_, _)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(_, _)

View file

@ -333,7 +333,7 @@ impl TyKind {
#[inline]
pub fn is_trait(&self) -> bool {
matches!(self, TyKind::RigidTy(RigidTy::Dynamic(_, _, DynKind::Dyn)))
matches!(self, TyKind::RigidTy(RigidTy::Dynamic(_, _)))
}
#[inline]
@ -472,7 +472,7 @@ impl TyKind {
}
pub fn trait_principal(&self) -> Option<Binder<ExistentialTraitRef>> {
if let TyKind::RigidTy(RigidTy::Dynamic(predicates, _, _)) = self {
if let TyKind::RigidTy(RigidTy::Dynamic(predicates, _)) = self {
if let Some(Binder { value: ExistentialPredicate::Trait(trait_ref), bound_vars }) =
predicates.first()
{
@ -562,7 +562,7 @@ pub enum RigidTy {
Closure(ClosureDef, GenericArgs),
Coroutine(CoroutineDef, GenericArgs),
CoroutineClosure(CoroutineClosureDef, GenericArgs),
Dynamic(Vec<Binder<ExistentialPredicate>>, Region, DynKind),
Dynamic(Vec<Binder<ExistentialPredicate>>, Region),
Never,
Tuple(Vec<Ty>),
CoroutineWitness(CoroutineWitnessDef, GenericArgs),
@ -1206,11 +1206,6 @@ pub enum BoundRegionKind {
BrEnv,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum DynKind {
Dyn,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum ExistentialPredicate {
Trait(ExistentialTraitRef),

View file

@ -14,7 +14,7 @@ use crate::mir::alloc::AllocId;
use crate::mir::mono::{Instance, MonoItem, StaticDef};
use crate::mir::{BinOp, Mutability, Place, ProjectionElem, RawPtrKind, Safety, UnOp};
use crate::ty::{
Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, DynKind,
Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind,
ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
GenericArgKind, GenericArgs, IntTy, MirConst, Movability, Pattern, Region, RigidTy, Span,
TermKind, TraitRef, Ty, TyConst, UintTy, VariantDef, VariantIdx,
@ -188,10 +188,9 @@ impl RustcInternal for RigidTy {
def.0.internal(tables, tcx),
args.internal(tables, tcx),
),
RigidTy::Dynamic(predicate, region, dyn_kind) => rustc_ty::TyKind::Dynamic(
RigidTy::Dynamic(predicate, region) => rustc_ty::TyKind::Dynamic(
tcx.mk_poly_existential_predicates(&predicate.internal(tables, tcx)),
region.internal(tables, tcx),
dyn_kind.internal(tables, tcx),
),
RigidTy::Tuple(tys) => {
rustc_ty::TyKind::Tuple(tcx.mk_type_list(&tys.internal(tables, tcx)))
@ -460,20 +459,6 @@ impl RustcInternal for BoundVariableKind {
}
}
impl RustcInternal for DynKind {
type T<'tcx> = rustc_ty::DynKind;
fn internal<'tcx>(
&self,
_tables: &mut Tables<'_, BridgeTys>,
_tcx: impl InternalCx<'tcx>,
) -> Self::T<'tcx> {
match self {
DynKind::Dyn => rustc_ty::DynKind::Dyn,
}
}
}
impl RustcInternal for ExistentialPredicate {
type T<'tcx> = rustc_ty::ExistentialPredicate<'tcx>;

View file

@ -48,16 +48,6 @@ impl<'tcx> Stable<'tcx> for ty::AliasTerm<'tcx> {
}
}
impl<'tcx> Stable<'tcx> for ty::DynKind {
type T = crate::ty::DynKind;
fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &CompilerCtxt<'_, BridgeTys>) -> Self::T {
match self {
ty::Dyn => crate::ty::DynKind::Dyn,
}
}
}
impl<'tcx> Stable<'tcx> for ty::ExistentialPredicate<'tcx> {
type T = crate::ty::ExistentialPredicate;
@ -439,16 +429,13 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
}
// FIXME(unsafe_binders):
ty::UnsafeBinder(_) => todo!(),
ty::Dynamic(existential_predicates, region, dyn_kind) => {
TyKind::RigidTy(RigidTy::Dynamic(
existential_predicates
.iter()
.map(|existential_predicate| existential_predicate.stable(tables, cx))
.collect(),
region.stable(tables, cx),
dyn_kind.stable(tables, cx),
))
}
ty::Dynamic(existential_predicates, region) => TyKind::RigidTy(RigidTy::Dynamic(
existential_predicates
.iter()
.map(|existential_predicate| existential_predicate.stable(tables, cx))
.collect(),
region.stable(tables, cx),
)),
ty::Closure(def_id, generic_args) => TyKind::RigidTy(RigidTy::Closure(
tables.closure_def(*def_id),
generic_args.stable(tables, cx),

View file

@ -171,7 +171,7 @@ impl Visitable for RigidTy {
| RigidTy::CoroutineClosure(_, args)
| RigidTy::FnDef(_, args) => args.visit(visitor),
RigidTy::FnPtr(sig) => sig.visit(visitor),
RigidTy::Dynamic(pred, r, _) => {
RigidTy::Dynamic(pred, r) => {
pred.visit(visitor)?;
r.visit(visitor)
}

View file

@ -626,12 +626,10 @@ pub(crate) fn encode_ty<'tcx>(
}
// Trait types
ty::Dynamic(predicates, region, kind) => {
ty::Dynamic(predicates, region) => {
// u3dynI<element-type1[..element-typeN]>E, where <element-type> is <predicate>, as
// vendor extended type.
let mut s = String::from(match kind {
ty::Dyn => "u3dynI",
});
let mut s = String::from("u3dynI");
s.push_str(&encode_predicates(tcx, predicates, dict, options));
s.push_str(&encode_region(*region, dict));
s.push('E');

View file

@ -268,7 +268,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
let preds = tcx.mk_poly_existential_predicates_from_iter(
iter::once(principal_pred).chain(assoc_preds.into_iter()),
);
Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased, ty::Dyn)
Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased)
}
/// Transforms an instance for LLVM CFI and cross-language LLVM CFI support using Itanium C++ ABI
@ -334,7 +334,7 @@ pub(crate) fn transform_instance<'tcx>(
ty::List::empty(),
));
let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased);
instance.args = tcx.mk_args_trait(self_ty, List::empty());
} else if let ty::InstanceKind::Virtual(def_id, _) = instance.def {
// Transform self into a trait object of the trait that defines the method for virtual
@ -347,7 +347,7 @@ pub(crate) fn transform_instance<'tcx>(
// drop_in_place won't have a defining trait, skip the upcast
None => instance.args.type_at(0),
};
let ty::Dynamic(preds, lifetime, kind) = upcast_ty.kind() else {
let ty::Dynamic(preds, lifetime) = upcast_ty.kind() else {
bug!("Tried to remove autotraits from non-dynamic type {upcast_ty}");
};
let self_ty = if preds.principal().is_some() {
@ -355,7 +355,7 @@ pub(crate) fn transform_instance<'tcx>(
tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
!matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
}));
Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind)
Ty::new_dynamic(tcx, filtered_preds, *lifetime)
} else {
// If there's no principal type, re-encode it as a unit, since we don't know anything
// about it. This technically discards the knowledge that it was a type that was made

View file

@ -110,7 +110,7 @@ impl<'tcx> AbiHashStable<'tcx> for Ty<'tcx> {
| ty::RawPtr(_, _)
| ty::FnDef(_, _)
| ty::FnPtr(_, _)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)

View file

@ -577,10 +577,8 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
// FIXME(unsafe_binder):
ty::UnsafeBinder(..) => todo!(),
ty::Dynamic(predicates, r, kind) => {
self.push(match kind {
ty::Dyn => "D",
});
ty::Dynamic(predicates, r) => {
self.push("D");
self.print_dyn_existential(predicates)?;
r.print(self)?;
}

View file

@ -399,7 +399,7 @@ pub struct TraitObjectVisitor(pub FxIndexSet<DefId>);
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for TraitObjectVisitor {
fn visit_ty(&mut self, t: Ty<'tcx>) {
match t.kind() {
ty::Dynamic(preds, re, _) if re.is_static() => {
ty::Dynamic(preds, re) if re.is_static() => {
if let Some(def_id) = preds.principal_def_id() {
self.0.insert(def_id);
}

View file

@ -292,7 +292,7 @@ impl<T> Trait<T> for X {
);
}
}
(ty::Dynamic(t, _, ty::DynKind::Dyn), ty::Alias(ty::Opaque, alias))
(ty::Dynamic(t, _), ty::Alias(ty::Opaque, alias))
if let Some(def_id) = t.principal_def_id()
&& tcx
.explicit_item_self_bounds(alias.def_id)
@ -314,9 +314,7 @@ impl<T> Trait<T> for X {
values.found, values.expected,
));
}
(ty::Dynamic(t, _, ty::DynKind::Dyn), _)
if let Some(def_id) = t.principal_def_id() =>
{
(ty::Dynamic(t, _), _) if let Some(def_id) = t.principal_def_id() => {
let mut has_matching_impl = false;
tcx.for_each_relevant_impl(def_id, values.found, |did| {
if DeepRejectCtxt::relate_rigid_infer(tcx)
@ -335,9 +333,7 @@ impl<T> Trait<T> for X {
));
}
}
(_, ty::Dynamic(t, _, ty::DynKind::Dyn))
if let Some(def_id) = t.principal_def_id() =>
{
(_, ty::Dynamic(t, _)) if let Some(def_id) = t.principal_def_id() => {
let mut has_matching_impl = false;
tcx.for_each_relevant_impl(def_id, values.expected, |did| {
if DeepRejectCtxt::relate_rigid_infer(tcx)
@ -489,7 +485,7 @@ impl<T> Trait<T> for X {
&& let Some(then) = blk.expr
&& def.is_box()
&& let boxed_ty = args.type_at(0)
&& let ty::Dynamic(t, _, _) = boxed_ty.kind()
&& let ty::Dynamic(t, _) = boxed_ty.kind()
&& let Some(def_id) = t.principal_def_id()
&& let mut impl_def_ids = vec![]
&& let _ =

View file

@ -430,7 +430,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut alt_span = None;
if let Some(ty) = ty
&& sub.is_static()
&& let ty::Dynamic(preds, _, ty::DynKind::Dyn) = ty.kind()
&& let ty::Dynamic(preds, _) = ty.kind()
&& let Some(def_id) = preds.principal_def_id()
{
for (clause, span) in

View file

@ -554,7 +554,7 @@ fn attempt_dyn_to_enum_suggestion(
// defaults to assuming that things are *not* sized, whereas we want to
// fall back to assuming that things may be sized.
match impl_type.kind() {
ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::DynKind::Dyn) => {
ty::Str | ty::Slice(_) | ty::Dynamic(_, _) => {
return None;
}
_ => {}

View file

@ -237,7 +237,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
}
if let ty::Dynamic(traits, _, _) = self_ty.kind() {
if let ty::Dynamic(traits, _) = self_ty.kind() {
for t in traits.iter() {
if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
self_types.push(self.tcx.def_path_str(trait_ref.def_id));

View file

@ -1131,7 +1131,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
},
)
}
ty::Dynamic(data, _, ty::Dyn) => data.iter().find_map(|pred| {
ty::Dynamic(data, _) => data.iter().find_map(|pred| {
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
&& self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput)
// for existential projection, args are shifted over by 1
@ -1520,7 +1520,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else {
return;
};
let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else {
let ty::Dynamic(predicates, _) = object_ty.kind() else {
return;
};
let self_ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, self_ty);
@ -1883,7 +1883,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let ObligationCauseCode::SizedReturnType = obligation.cause.code() else {
return false;
};
let ty::Dynamic(_, _, ty::Dyn) = trait_pred.self_ty().skip_binder().kind() else {
let ty::Dynamic(_, _) = trait_pred.self_ty().skip_binder().kind() else {
return false;
};

View file

@ -669,7 +669,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// These may potentially implement `FnPtr`
ty::Placeholder(..)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Alias(_, _)
| ty::Infer(_)
| ty::Param(..)
@ -991,7 +991,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match (source.kind(), target.kind()) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
(&ty::Dynamic(a_data, a_region, ty::Dyn), &ty::Dynamic(b_data, b_region, ty::Dyn)) => {
(&ty::Dynamic(a_data, a_region), &ty::Dynamic(b_data, b_region)) => {
// Upcast coercions permit several things:
//
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
@ -1054,7 +1054,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// `T` -> `Trait`
(_, &ty::Dynamic(_, _, ty::Dyn)) => {
(_, &ty::Dynamic(_, _)) => {
candidates.vec.push(BuiltinUnsizeCandidate);
}
@ -1327,7 +1327,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Pat(_, _)
| ty::FnPtr(..)
| ty::UnsafeBinder(_)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(_, _)

View file

@ -1023,10 +1023,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let a_ty = self.infcx.shallow_resolve(predicate.self_ty());
let b_ty = self.infcx.shallow_resolve(predicate.trait_ref.args.type_at(1));
let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else {
let ty::Dynamic(a_data, a_region) = *a_ty.kind() else {
bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`")
};
let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else {
let ty::Dynamic(b_data, b_region) = *b_ty.kind() else {
bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`")
};
@ -1062,10 +1062,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?source, ?target, "confirm_builtin_unsize_candidate");
Ok(match (source.kind(), target.kind()) {
// Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
(&ty::Dynamic(data_a, r_a, dyn_a), &ty::Dynamic(data_b, r_b, dyn_b))
if dyn_a == dyn_b =>
{
// `dyn Trait + Kx + 'a` -> `dyn Trait + Ky + 'b` (auto traits and lifetime subtyping).
(&ty::Dynamic(data_a, r_a), &ty::Dynamic(data_b, r_b)) => {
// See `assemble_candidates_for_unsizing` for more info.
// We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
let existential_predicates = if data_b.principal().is_some() {
@ -1098,7 +1096,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map(ty::Binder::dummy),
)
};
let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, dyn_a);
let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b);
// Require that the traits involved in this upcast are **equal**;
// only the **lifetime bound** is changed.
@ -1122,7 +1120,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// `T` -> `dyn Trait`
(_, &ty::Dynamic(data, r, ty::Dyn)) => {
(_, &ty::Dynamic(data, r)) => {
let mut object_dids = data.auto_traits().chain(data.principal_def_id());
if let Some(did) = object_dids.find(|did| !tcx.is_dyn_compatible(*did)) {
return Err(SelectionError::TraitDynIncompatible(did));

View file

@ -317,7 +317,7 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe
"vtable trait ref should be normalized"
);
let ty::Dynamic(source, _, _) = *key.self_ty().kind() else {
let ty::Dynamic(source, _) = *key.self_ty().kind() else {
bug!();
};
let source_principal = tcx.instantiate_bound_regions_with_erased(
@ -384,13 +384,13 @@ pub(crate) fn supertrait_vtable_slot<'tcx>(
let (source, target) = key;
// If the target principal is `None`, we can just return `None`.
let ty::Dynamic(target_data, _, _) = *target.kind() else {
let ty::Dynamic(target_data, _) = *target.kind() else {
bug!();
};
let target_principal = tcx.instantiate_bound_regions_with_erased(target_data.principal()?);
// Given that we have a target principal, it is a bug for there not to be a source principal.
let ty::Dynamic(source_data, _, _) = *source.kind() else {
let ty::Dynamic(source_data, _) = *source.kind() else {
bug!();
};
let source_principal = tcx.instantiate_bound_regions_with_erased(

View file

@ -915,7 +915,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
// We recurse into the binder below.
}
ty::Dynamic(data, r, _) => {
ty::Dynamic(data, r) => {
// WfObject
//
// Here, we defer WF checking due to higher-ranked

View file

@ -476,7 +476,7 @@ fn layout_of_uncached<'tcx>(
}
// Odd unit types.
ty::FnDef(..) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
ty::FnDef(..) | ty::Dynamic(_, _) | ty::Foreign(..) => {
let sized = matches!(ty.kind(), ty::FnDef(..));
tcx.mk_layout(LayoutData::unit(cx, sized))
}

View file

@ -40,7 +40,7 @@ fn sizedness_constraint_for_ty<'tcx>(
| ty::CoroutineWitness(..)
| ty::Never => None,
ty::Str | ty::Slice(..) | ty::Dynamic(_, _, ty::Dyn) => match sizedness {
ty::Str | ty::Slice(..) | ty::Dynamic(_, _) => match sizedness {
// Never `Sized`
SizedTraitKind::Sized => Some(ty),
// Always `MetaSized`
@ -366,7 +366,7 @@ fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId)
);
match tail.kind() {
ty::Dynamic(_, _, ty::Dyn) | ty::Slice(_) | ty::Str => true,
ty::Dynamic(_, _) | ty::Slice(_) | ty::Str => true,
ty::Bool
| ty::Char
| ty::Int(_)

View file

@ -288,7 +288,7 @@ impl<I: Interner> FlagComputation<I> {
self.add_alias_ty(data);
}
ty::Dynamic(obj, r, _) => {
ty::Dynamic(obj, r) => {
for predicate in obj.iter() {
self.bound_computation(predicate, |computation, predicate| match predicate {
ty::ExistentialPredicate::Trait(tr) => {

View file

@ -76,12 +76,7 @@ pub trait Ty<I: Interner<Ty = Self>>:
fn new_foreign(interner: I, def_id: I::ForeignId) -> Self;
fn new_dynamic(
interner: I,
preds: I::BoundExistentialPredicates,
region: I::Region,
kind: ty::DynKind,
) -> Self;
fn new_dynamic(interner: I, preds: I::BoundExistentialPredicates, region: I::Region) -> Self;
fn new_coroutine(interner: I, def_id: I::CoroutineId, args: I::GenericArgs) -> Self;
@ -167,7 +162,7 @@ pub trait Ty<I: Interner<Ty = Self>>:
fn is_guaranteed_unsized_raw(self) -> bool {
match self.kind() {
ty::Dynamic(_, _, ty::Dyn) | ty::Slice(_) | ty::Str => true,
ty::Dynamic(_, _) | ty::Slice(_) | ty::Str => true,
ty::Bool
| ty::Char
| ty::Int(_)

View file

@ -57,7 +57,6 @@ mod upcast;
mod visit;
pub use AliasTyKind::*;
pub use DynKind::*;
pub use InferTy::*;
pub use RegionKind::*;
pub use TyKind::*;

View file

@ -203,7 +203,7 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
| ty::Ref(_, _, _)
| ty::FnPtr(..)
| ty::UnsafeBinder(_)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Tuple(_) => {
ty.super_visit_with(self);
}

View file

@ -412,16 +412,11 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>(
(ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(cx, a_id)),
(ty::Dynamic(a_obj, a_region, a_repr), ty::Dynamic(b_obj, b_region, b_repr))
if a_repr == b_repr =>
{
Ok(Ty::new_dynamic(
cx,
relation.relate(a_obj, b_obj)?,
relation.relate(a_region, b_region)?,
a_repr,
))
}
(ty::Dynamic(a_obj, a_region), ty::Dynamic(b_obj, b_region)) => Ok(Ty::new_dynamic(
cx,
relation.relate(a_obj, b_obj)?,
relation.relate(a_region, b_region)?,
)),
(ty::Coroutine(a_id, a_args), ty::Coroutine(b_id, b_args)) if a_id == b_id => {
// All Coroutine types with the same id represent

View file

@ -19,20 +19,6 @@ use crate::{self as ty, DebruijnIndex, FloatTy, IntTy, Interner, UintTy};
mod closure;
/// Specifies how a trait object is represented.
///
/// This used to have a variant `DynStar`, but that variant has been removed,
/// and it's likely this whole enum will be removed soon.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(
feature = "nightly",
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
)]
pub enum DynKind {
/// An unsized `dyn Trait` object
Dyn,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(
feature = "nightly",
@ -165,7 +151,7 @@ pub enum TyKind<I: Interner> {
UnsafeBinder(UnsafeBinderInner<I>),
/// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`.
Dynamic(I::BoundExistentialPredicates, I::Region, DynKind),
Dynamic(I::BoundExistentialPredicates, I::Region),
/// The anonymous type of a closure. Used to represent the type of `|a| a`.
///
@ -314,7 +300,7 @@ impl<I: Interner> TyKind<I> {
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::UnsafeBinder(_)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
@ -367,9 +353,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
FnPtr(sig_tys, hdr) => write!(f, "{:?}", sig_tys.with(*hdr)),
// FIXME(unsafe_binder): print this like `unsafe<'a> T<'a>`.
UnsafeBinder(binder) => write!(f, "{:?}", binder),
Dynamic(p, r, repr) => match repr {
DynKind::Dyn => write!(f, "dyn {p:?} + {r:?}"),
},
Dynamic(p, r) => write!(f, "dyn {p:?} + {r:?}"),
Closure(d, s) => f.debug_tuple("Closure").field(d).field(&s).finish(),
CoroutineClosure(d, s) => f.debug_tuple("CoroutineClosure").field(d).field(&s).finish(),
Coroutine(d, s) => f.debug_tuple("Coroutine").field(d).field(&s).finish(),

View file

@ -109,7 +109,7 @@ fn push_inner<I: Interner>(stack: &mut TypeWalkerStack<I>, parent: I::GenericArg
ty::Alias(_, data) => {
stack.extend(data.args.iter().rev());
}
ty::Dynamic(obj, lt, _) => {
ty::Dynamic(obj, lt) => {
stack.push(lt.into());
stack.extend(
obj.iter()

View file

@ -2093,7 +2093,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
);
Type::Path { path }
}
ty::Dynamic(obj, reg, _) => {
ty::Dynamic(obj, reg) => {
// HACK: pick the first `did` as the `did` of the trait object. Someone
// might want to implement "native" support for marker-trait-only
// trait objects.

View file

@ -86,7 +86,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, msrv: Msrv)
ty::FnPtr(..) => {
return Err((span, "function pointers in const fn are unstable".into()));
},
ty::Dynamic(preds, _, _) => {
ty::Dynamic(preds, _) => {
for pred in *preds {
match pred.skip_binder() {
ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => {

View file

@ -349,7 +349,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
}
false
},
ty::Dynamic(binder, _, _) => {
ty::Dynamic(binder, _) => {
for predicate in *binder {
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
&& find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { .. })
@ -673,7 +673,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
cx.tcx.opt_parent(def_id),
),
ty::FnPtr(sig_tys, hdr) => Some(ExprFnSig::Sig(sig_tys.with(hdr), None)),
ty::Dynamic(bounds, _, _) => {
ty::Dynamic(bounds, _) => {
let lang_items = cx.tcx.lang_items();
match bounds.principal() {
Some(bound)