summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/astconv
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /compiler/rustc_hir_analysis/src/astconv
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_analysis/src/astconv')
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs575
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/lint.rs124
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs1296
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/object_safety.rs408
5 files changed, 1275 insertions, 1154 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
new file mode 100644
index 000000000..b13de7701
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -0,0 +1,575 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_lint_defs::Applicability;
+use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
+use rustc_span::symbol::Ident;
+use rustc_span::{ErrorGuaranteed, Span};
+use rustc_trait_selection::traits;
+
+use crate::astconv::{
+ AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
+};
+use crate::bounds::Bounds;
+use crate::errors::{MultipleRelaxedDefaultBounds, ValueOfAssociatedStructAlreadySpecified};
+
+impl<'tcx> dyn AstConv<'tcx> + '_ {
+ /// Sets `implicitly_sized` to true on `Bounds` if necessary
+ pub(crate) fn add_implicitly_sized(
+ &self,
+ bounds: &mut Bounds<'tcx>,
+ self_ty: Ty<'tcx>,
+ ast_bounds: &'tcx [hir::GenericBound<'tcx>],
+ self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+ span: Span,
+ ) {
+ let tcx = self.tcx();
+
+ // Try to find an unbound in bounds.
+ let mut unbound = None;
+ let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
+ for ab in ast_bounds {
+ if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
+ if unbound.is_none() {
+ unbound = Some(&ptr.trait_ref);
+ } else {
+ tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span });
+ }
+ }
+ }
+ };
+ search_bounds(ast_bounds);
+ if let Some((self_ty, where_clause)) = self_ty_where_predicates {
+ for clause in where_clause {
+ if let hir::WherePredicate::BoundPredicate(pred) = clause {
+ if pred.is_param_bound(self_ty.to_def_id()) {
+ search_bounds(pred.bounds);
+ }
+ }
+ }
+ }
+
+ let sized_def_id = tcx.lang_items().sized_trait();
+ match (&sized_def_id, unbound) {
+ (Some(sized_def_id), Some(tpb))
+ if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) =>
+ {
+ // There was in fact a `?Sized` bound, return without doing anything
+ return;
+ }
+ (_, Some(_)) => {
+ // There was a `?Trait` bound, but it was not `?Sized`; warn.
+ tcx.sess.span_warn(
+ span,
+ "default bound relaxed for a type parameter, but \
+ this does nothing because the given bound is not \
+ a default; only `?Sized` is supported",
+ );
+ // Otherwise, add implicitly sized if `Sized` is available.
+ }
+ _ => {
+ // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
+ }
+ }
+ if sized_def_id.is_none() {
+ // No lang item for `Sized`, so we can't add it as a bound.
+ return;
+ }
+ bounds.push_sized(tcx, self_ty, span);
+ }
+
+ /// This helper takes a *converted* parameter type (`param_ty`)
+ /// and an *unconverted* list of bounds:
+ ///
+ /// ```text
+ /// fn foo<T: Debug>
+ /// ^ ^^^^^ `ast_bounds` parameter, in HIR form
+ /// |
+ /// `param_ty`, in ty form
+ /// ```
+ ///
+ /// It adds these `ast_bounds` into the `bounds` structure.
+ ///
+ /// **A note on binders:** there is an implied binder around
+ /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
+ /// for more details.
+ #[instrument(level = "debug", skip(self, ast_bounds, bounds))]
+ pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>>(
+ &self,
+ param_ty: Ty<'tcx>,
+ ast_bounds: I,
+ bounds: &mut Bounds<'tcx>,
+ bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
+ only_self_bounds: OnlySelfBounds,
+ ) {
+ for ast_bound in ast_bounds {
+ match ast_bound {
+ hir::GenericBound::Trait(poly_trait_ref, modifier) => {
+ let (constness, polarity) = match modifier {
+ hir::TraitBoundModifier::MaybeConst => {
+ (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
+ }
+ hir::TraitBoundModifier::None => {
+ (ty::BoundConstness::NotConst, ty::ImplPolarity::Positive)
+ }
+ hir::TraitBoundModifier::Negative => {
+ (ty::BoundConstness::NotConst, ty::ImplPolarity::Negative)
+ }
+ hir::TraitBoundModifier::Maybe => continue,
+ };
+ let _ = self.instantiate_poly_trait_ref(
+ &poly_trait_ref.trait_ref,
+ poly_trait_ref.span,
+ constness,
+ polarity,
+ param_ty,
+ bounds,
+ false,
+ only_self_bounds,
+ );
+ }
+ &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
+ self.instantiate_lang_item_trait_ref(
+ lang_item,
+ span,
+ hir_id,
+ args,
+ param_ty,
+ bounds,
+ only_self_bounds,
+ );
+ }
+ hir::GenericBound::Outlives(lifetime) => {
+ let region = self.ast_region_to_region(lifetime, None);
+ bounds.push_region_bound(
+ self.tcx(),
+ ty::Binder::bind_with_vars(
+ ty::OutlivesPredicate(param_ty, region),
+ bound_vars,
+ ),
+ lifetime.ident.span,
+ );
+ }
+ }
+ }
+ }
+
+ /// Translates a list of bounds from the HIR into the `Bounds` data structure.
+ /// The self-type for the bounds is given by `param_ty`.
+ ///
+ /// Example:
+ ///
+ /// ```ignore (illustrative)
+ /// fn foo<T: Bar + Baz>() { }
+ /// // ^ ^^^^^^^^^ ast_bounds
+ /// // param_ty
+ /// ```
+ ///
+ /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
+ /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
+ /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
+ ///
+ /// `span` should be the declaration size of the parameter.
+ pub(crate) fn compute_bounds(
+ &self,
+ param_ty: Ty<'tcx>,
+ ast_bounds: &[hir::GenericBound<'_>],
+ filter: PredicateFilter,
+ ) -> Bounds<'tcx> {
+ let mut bounds = Bounds::default();
+
+ let only_self_bounds = match filter {
+ PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
+ OnlySelfBounds(false)
+ }
+ PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => OnlySelfBounds(true),
+ };
+
+ self.add_bounds(
+ param_ty,
+ ast_bounds.iter().filter(|bound| {
+ match filter {
+ PredicateFilter::All
+ | PredicateFilter::SelfOnly
+ | PredicateFilter::SelfAndAssociatedTypeBounds => true,
+ PredicateFilter::SelfThatDefines(assoc_name) => {
+ if let Some(trait_ref) = bound.trait_ref()
+ && let Some(trait_did) = trait_ref.trait_def_id()
+ && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
+ {
+ true
+ } else {
+ false
+ }
+ }
+ }
+ }),
+ &mut bounds,
+ ty::List::empty(),
+ only_self_bounds,
+ );
+ debug!(?bounds);
+
+ bounds
+ }
+
+ /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates
+ /// onto `bounds`.
+ ///
+ /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
+ /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
+ /// the binder (e.g., `&'a u32`) and hence may reference bound regions.
+ #[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))]
+ pub(super) fn add_predicates_for_ast_type_binding(
+ &self,
+ hir_ref_id: hir::HirId,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ binding: &ConvertedBinding<'_, 'tcx>,
+ bounds: &mut Bounds<'tcx>,
+ speculative: bool,
+ dup_bindings: &mut FxHashMap<DefId, Span>,
+ path_span: Span,
+ constness: ty::BoundConstness,
+ only_self_bounds: OnlySelfBounds,
+ polarity: ty::ImplPolarity,
+ ) -> Result<(), ErrorGuaranteed> {
+ // Given something like `U: SomeTrait<T = X>`, we want to produce a
+ // predicate like `<U as SomeTrait>::T = X`. This is somewhat
+ // subtle in the event that `T` is defined in a supertrait of
+ // `SomeTrait`, because in that case we need to upcast.
+ //
+ // That is, consider this case:
+ //
+ // ```
+ // trait SubTrait: SuperTrait<i32> { }
+ // trait SuperTrait<A> { type T; }
+ //
+ // ... B: SubTrait<T = foo> ...
+ // ```
+ //
+ // We want to produce `<B as SuperTrait<i32>>::T == foo`.
+
+ let tcx = self.tcx();
+
+ let return_type_notation =
+ binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation;
+
+ let candidate = if return_type_notation {
+ if self.trait_defines_associated_item_named(
+ trait_ref.def_id(),
+ ty::AssocKind::Fn,
+ binding.item_name,
+ ) {
+ trait_ref
+ } else {
+ self.one_bound_for_assoc_method(
+ traits::supertraits(tcx, trait_ref),
+ trait_ref.print_only_trait_path(),
+ binding.item_name,
+ path_span,
+ )?
+ }
+ } else if self.trait_defines_associated_item_named(
+ trait_ref.def_id(),
+ ty::AssocKind::Type,
+ binding.item_name,
+ ) {
+ // Simple case: X is defined in the current trait.
+ trait_ref
+ } else {
+ // Otherwise, we have to walk through the supertraits to find
+ // those that do.
+ self.one_bound_for_assoc_type(
+ || traits::supertraits(tcx, trait_ref),
+ trait_ref.skip_binder().print_only_trait_name(),
+ binding.item_name,
+ path_span,
+ match binding.kind {
+ ConvertedBindingKind::Equality(term) => Some(term),
+ _ => None,
+ },
+ )?
+ };
+
+ let (assoc_ident, def_scope) =
+ tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
+
+ // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
+ // of calling `filter_by_name_and_kind`.
+ let find_item_of_kind = |kind| {
+ tcx.associated_items(candidate.def_id())
+ .filter_by_name_unhygienic(assoc_ident.name)
+ .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
+ };
+ let assoc_item = if return_type_notation {
+ find_item_of_kind(ty::AssocKind::Fn)
+ } else {
+ find_item_of_kind(ty::AssocKind::Type)
+ .or_else(|| find_item_of_kind(ty::AssocKind::Const))
+ }
+ .expect("missing associated type");
+
+ if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
+ tcx.sess
+ .struct_span_err(
+ binding.span,
+ format!("{} `{}` is private", assoc_item.kind, binding.item_name),
+ )
+ .span_label(binding.span, format!("private {}", assoc_item.kind))
+ .emit();
+ }
+ tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
+
+ if !speculative {
+ dup_bindings
+ .entry(assoc_item.def_id)
+ .and_modify(|prev_span| {
+ tcx.sess.emit_err(ValueOfAssociatedStructAlreadySpecified {
+ span: binding.span,
+ prev_span: *prev_span,
+ item_name: binding.item_name,
+ def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
+ });
+ })
+ .or_insert(binding.span);
+ }
+
+ let projection_ty = if return_type_notation {
+ let mut emitted_bad_param_err = false;
+ // If we have an method return type bound, then we need to substitute
+ // the method's early bound params with suitable late-bound params.
+ let mut num_bound_vars = candidate.bound_vars().len();
+ let substs =
+ candidate.skip_binder().substs.extend_to(tcx, assoc_item.def_id, |param, _| {
+ let subst = match param.kind {
+ ty::GenericParamDefKind::Lifetime => ty::Region::new_late_bound(
+ tcx,
+ ty::INNERMOST,
+ ty::BoundRegion {
+ var: ty::BoundVar::from_usize(num_bound_vars),
+ kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name),
+ },
+ )
+ .into(),
+ ty::GenericParamDefKind::Type { .. } => {
+ if !emitted_bad_param_err {
+ tcx.sess.emit_err(
+ crate::errors::ReturnTypeNotationIllegalParam::Type {
+ span: path_span,
+ param_span: tcx.def_span(param.def_id),
+ },
+ );
+ emitted_bad_param_err = true;
+ }
+ Ty::new_bound(
+ tcx,
+ ty::INNERMOST,
+ ty::BoundTy {
+ var: ty::BoundVar::from_usize(num_bound_vars),
+ kind: ty::BoundTyKind::Param(param.def_id, param.name),
+ },
+ )
+ .into()
+ }
+ ty::GenericParamDefKind::Const { .. } => {
+ if !emitted_bad_param_err {
+ tcx.sess.emit_err(
+ crate::errors::ReturnTypeNotationIllegalParam::Const {
+ span: path_span,
+ param_span: tcx.def_span(param.def_id),
+ },
+ );
+ emitted_bad_param_err = true;
+ }
+ let ty = tcx
+ .type_of(param.def_id)
+ .no_bound_vars()
+ .expect("ct params cannot have early bound vars");
+ ty::Const::new_bound(
+ tcx,
+ ty::INNERMOST,
+ ty::BoundVar::from_usize(num_bound_vars),
+ ty,
+ )
+ .into()
+ }
+ };
+ num_bound_vars += 1;
+ subst
+ });
+
+ // Next, we need to check that the return-type notation is being used on
+ // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait).
+ let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output();
+ let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
+ && tcx.is_impl_trait_in_trait(alias_ty.def_id)
+ {
+ alias_ty
+ } else {
+ return Err(self.tcx().sess.emit_err(
+ crate::errors::ReturnTypeNotationOnNonRpitit {
+ span: binding.span,
+ ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
+ fn_span: tcx.hir().span_if_local(assoc_item.def_id),
+ note: (),
+ },
+ ));
+ };
+
+ // Finally, move the fn return type's bound vars over to account for the early bound
+ // params (and trait ref's late bound params). This logic is very similar to
+ // `Predicate::subst_supertrait`, and it's no coincidence why.
+ let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
+ let subst_output = ty::EarlyBinder::bind(shifted_output).subst(tcx, substs);
+
+ let bound_vars = tcx.late_bound_vars(binding.hir_id);
+ ty::Binder::bind_with_vars(subst_output, bound_vars)
+ } else {
+ // Include substitutions for generic parameters of associated types
+ candidate.map_bound(|trait_ref| {
+ let ident = Ident::new(assoc_item.name, binding.item_name.span);
+ let item_segment = hir::PathSegment {
+ ident,
+ hir_id: binding.hir_id,
+ res: Res::Err,
+ args: Some(binding.gen_args),
+ infer_args: false,
+ };
+
+ let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
+ path_span,
+ assoc_item.def_id,
+ &item_segment,
+ trait_ref.substs,
+ );
+
+ debug!(?substs_trait_ref_and_assoc_item);
+
+ tcx.mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
+ })
+ };
+
+ if !speculative {
+ // Find any late-bound regions declared in `ty` that are not
+ // declared in the trait-ref or assoc_item. These are not well-formed.
+ //
+ // Example:
+ //
+ // for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
+ // for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
+ if let ConvertedBindingKind::Equality(ty) = binding.kind {
+ let late_bound_in_trait_ref =
+ tcx.collect_constrained_late_bound_regions(&projection_ty);
+ let late_bound_in_ty =
+ tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
+ debug!(?late_bound_in_trait_ref);
+ debug!(?late_bound_in_ty);
+
+ // FIXME: point at the type params that don't have appropriate lifetimes:
+ // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
+ // ---- ---- ^^^^^^^
+ self.validate_late_bound_regions(
+ late_bound_in_trait_ref,
+ late_bound_in_ty,
+ |br_name| {
+ struct_span_err!(
+ tcx.sess,
+ binding.span,
+ E0582,
+ "binding for associated type `{}` references {}, \
+ which does not appear in the trait input types",
+ binding.item_name,
+ br_name
+ )
+ },
+ );
+ }
+ }
+
+ match binding.kind {
+ ConvertedBindingKind::Equality(..) if return_type_notation => {
+ return Err(self.tcx().sess.emit_err(
+ crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
+ ));
+ }
+ ConvertedBindingKind::Equality(mut term) => {
+ // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
+ // the "projection predicate" for:
+ //
+ // `<T as Iterator>::Item = u32`
+ let assoc_item_def_id = projection_ty.skip_binder().def_id;
+ let def_kind = tcx.def_kind(assoc_item_def_id);
+ match (def_kind, term.unpack()) {
+ (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_))
+ | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (),
+ (_, _) => {
+ let got = if let Some(_) = term.ty() { "type" } else { "constant" };
+ let expected = tcx.def_descr(assoc_item_def_id);
+ let mut err = tcx.sess.struct_span_err(
+ binding.span,
+ format!("expected {expected} bound, found {got}"),
+ );
+ err.span_note(
+ tcx.def_span(assoc_item_def_id),
+ format!("{expected} defined here"),
+ );
+
+ if let hir::def::DefKind::AssocConst = def_kind
+ && let Some(t) = term.ty() && (t.is_enum() || t.references_error())
+ && tcx.features().associated_const_equality {
+ err.span_suggestion(
+ binding.span,
+ "if equating a const, try wrapping with braces",
+ format!("{} = {{ const }}", binding.item_name),
+ Applicability::HasPlaceholders,
+ );
+ }
+ let reported = err.emit();
+ term = match def_kind {
+ hir::def::DefKind::AssocTy => Ty::new_error(tcx, reported).into(),
+ hir::def::DefKind::AssocConst => ty::Const::new_error(
+ tcx,
+ reported,
+ tcx.type_of(assoc_item_def_id)
+ .subst(tcx, projection_ty.skip_binder().substs),
+ )
+ .into(),
+ _ => unreachable!(),
+ };
+ }
+ }
+ bounds.push_projection_bound(
+ tcx,
+ projection_ty
+ .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
+ binding.span,
+ );
+ }
+ ConvertedBindingKind::Constraint(ast_bounds) => {
+ // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
+ //
+ // `<T as Iterator>::Item: Debug`
+ //
+ // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
+ // parameter to have a skipped binder.
+ //
+ // NOTE: If `only_self_bounds` is true, do NOT expand this associated
+ // type bound into a trait predicate, since we only want to add predicates
+ // for the `Self` type.
+ if !only_self_bounds.0 {
+ let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
+ self.add_bounds(
+ param_ty,
+ ast_bounds.iter(),
+ bounds,
+ projection_ty.bound_vars(),
+ only_self_bounds,
+ );
+ }
+ }
+ }
+ Ok(())
+ }
+}
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index 7b922f5d5..ddf99853b 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -122,9 +122,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let all_candidate_names: Vec<_> = all_candidates()
.flat_map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
- .filter_map(
- |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None },
- )
+ .filter_map(|item| {
+ if item.opt_rpitit_info.is_none() && item.kind == ty::AssocKind::Type {
+ Some(item.name)
+ } else {
+ None
+ }
+ })
.collect();
if let (Some(suggested_name), true) = (
@@ -159,9 +163,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.flat_map(|trait_def_id| {
self.tcx().associated_items(*trait_def_id).in_definition_order()
})
- .filter_map(
- |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None },
- )
+ .filter_map(|item| {
+ if item.opt_rpitit_info.is_none() && item.kind == ty::AssocKind::Type {
+ Some(item.name)
+ } else {
+ None
+ }
+ })
.collect();
if let (Some(suggested_name), true) = (
@@ -343,13 +351,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let format_pred = |pred: ty::Predicate<'tcx>| {
let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
let pred = bound_predicate.rebind(pred);
// `<Foo as Iterator>::Item = String`.
let projection_ty = pred.skip_binder().projection_ty;
let substs_with_infer_self = tcx.mk_substs_from_iter(
- std::iter::once(tcx.mk_ty_var(ty::TyVid::from_u32(0)).into())
+ std::iter::once(Ty::new_var(tcx, ty::TyVid::from_u32(0)).into())
.chain(projection_ty.substs.iter().skip(1)),
);
@@ -364,7 +372,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty()))
}
- ty::PredicateKind::Clause(ty::Clause::Trait(poly_trait_ref)) => {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => {
let p = poly_trait_ref.trait_ref;
let self_ty = p.self_ty();
let path = p.print_only_trait_path();
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
new file mode 100644
index 000000000..05a3ab63d
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -0,0 +1,124 @@
+use rustc_ast::TraitObjectSyntax;
+use rustc_errors::{Diagnostic, StashKey};
+use rustc_hir as hir;
+use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
+use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
+
+use super::AstConv;
+
+impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
+ /// Make sure that we are in the condition to suggest the blanket implementation.
+ pub(super) fn maybe_lint_blanket_trait_impl(
+ &self,
+ self_ty: &hir::Ty<'_>,
+ diag: &mut Diagnostic,
+ ) {
+ 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: Some(of_trait_ref), generics, ..
+ }),
+ ..
+ }) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
+ {
+ if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
+ return;
+ }
+ let of_trait_span = of_trait_ref.path.span;
+ // make sure that we are not calling unwrap to abort during the compilation
+ let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
+ let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
+ // 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))
+ };
+ diag.multipart_suggestion(
+ format!("alternatively use a blanket \
+ implementation to implement `{of_trait_name}` for \
+ all types that also implement `{impl_trait_name}`"),
+ vec![
+ (self_ty.span, param_name),
+ add_generic_sugg,
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+
+ pub(super) fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
+ let tcx = self.tcx();
+ if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
+ self_ty.kind
+ {
+ 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::from_iter([(
+ 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().rust_2021() {
+ let msg = "trait objects must include the `dyn` keyword";
+ let label = "add `dyn` keyword before this trait";
+ let mut diag =
+ rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
+ if self_ty.span.can_be_used_for_suggestions() {
+ diag.multipart_suggestion_verbose(
+ label,
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ // check if the impl trait that we are considering is a impl of a local trait
+ self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
+ diag.stash(self_ty.span, StashKey::TraitMissingMethod);
+ } else {
+ let msg = "trait objects without an explicit `dyn` are deprecated";
+ tcx.struct_span_lint_hir(
+ BARE_TRAIT_OBJECTS,
+ self_ty.hir_id,
+ self_ty.span,
+ msg,
+ |lint| {
+ lint.multipart_suggestion_verbose(
+ "use `dyn`",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ self.maybe_lint_blanket_trait_impl(&self_ty, lint);
+ lint
+ },
+ );
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 2c60a0624..3d6984628 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2,53 +2,45 @@
//! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an
//! instance of `AstConv`.
+mod bounds;
mod errors;
pub mod generics;
+mod lint;
+mod object_safety;
use crate::astconv::errors::prohibit_assoc_ty_binding;
use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generic_args};
use crate::bounds::Bounds;
use crate::collect::HirPlaceholderCollector;
-use crate::errors::{
- AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits,
- TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified,
-};
+use crate::errors::{AmbiguousLifetimeBound, TypeofReservedKeywordUsed};
use crate::middle::resolve_bound_vars as rbv;
use crate::require_c_abi_if_c_variadic;
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
- MultiSpan, StashKey,
+ MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
-use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
use rustc_middle::middle::stability::AllowUnstable;
-use rustc_middle::ty::fold::FnMutDelegate;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
-use rustc_middle::ty::{DynKind, ToPredicate};
-use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
+use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_target::spec::abi;
-use rustc_trait_selection::traits::error_reporting::{
- report_object_safety_error, suggestions::NextTypeParamName,
-};
use rustc_trait_selection::traits::wf::object_region_bounds;
-use rustc_trait_selection::traits::{self, astconv_object_safety_violations, ObligationCtxt};
+use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCtxt};
+use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
-use smallvec::{smallvec, SmallVec};
-use std::collections::BTreeSet;
use std::fmt::Display;
use std::slice;
@@ -58,6 +50,24 @@ pub struct PathSeg(pub DefId, pub usize);
#[derive(Copy, Clone, Debug)]
pub struct OnlySelfBounds(pub bool);
+#[derive(Copy, Clone, Debug)]
+pub enum PredicateFilter {
+ /// All predicates may be implied by the trait.
+ All,
+
+ /// Only traits that reference `Self: ..` are implied by the trait.
+ SelfOnly,
+
+ /// Only traits that reference `Self: ..` and define an associated type
+ /// with the given ident are implied by the trait.
+ SelfThatDefines(Ident),
+
+ /// Only traits that reference `Self: ..` and their associated type bounds.
+ /// For example, given `Self: Tr<A: B>`, this would expand to `Self: Tr`
+ /// and `<Self as Tr>::A: B`.
+ SelfAndAssociatedTypeBounds,
+}
+
pub trait AstConv<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx>;
@@ -239,7 +249,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
var: ty::BoundVar::from_u32(index),
kind: ty::BrNamed(def_id, name),
};
- tcx.mk_re_late_bound(debruijn, br)
+ ty::Region::new_late_bound(tcx, debruijn, br)
}
Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
@@ -247,12 +257,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
- tcx.mk_re_early_bound(ty::EarlyBoundRegion { def_id, index, name })
+ ty::Region::new_early_bound(tcx, ty::EarlyBoundRegion { def_id, index, name })
}
Some(rbv::ResolvedArg::Free(scope, id)) => {
let name = lifetime_name(id.expect_local());
- tcx.mk_re_free(scope, ty::BrNamed(id, name))
+ ty::Region::new_free(tcx, scope, ty::BrNamed(id, name))
// (*) -- not late-bound, won't change
}
@@ -269,7 +279,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// elision. `resolve_lifetime` should have
// reported an error in this case -- but if
// not, let's error out.
- tcx.mk_re_error_with_message(
+ ty::Region::new_error_with_message(
+ tcx,
lifetime.ident.span,
"unelided lifetime in signature",
)
@@ -432,7 +443,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
if let (hir::TyKind::Infer, false) = (&ty.kind, self.astconv.allow_ty_infer()) {
self.inferred_params.push(ty.span);
- tcx.ty_error_misc().into()
+ Ty::new_misc_error(tcx).into()
} else {
self.astconv.ast_ty_to_ty(ty).into()
}
@@ -463,7 +474,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.astconv.ct_infer(ty, Some(param), inf.span).into()
} else {
self.inferred_params.push(inf.span);
- tcx.const_error_misc(ty).into()
+ ty::Const::new_misc_error(tcx, ty).into()
}
}
_ => unreachable!(),
@@ -485,7 +496,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!(?param, "unelided lifetime in signature");
// This indicates an illegal lifetime in a non-assoc-trait position
- tcx.mk_re_error_with_message(
+ ty::Region::new_error_with_message(
+ tcx,
self.span,
"unelided lifetime in signature",
)
@@ -500,14 +512,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
_ => false,
}) {
// Avoid ICE #86756 when type error recovery goes awry.
- return tcx.ty_error_misc().into();
+ return Ty::new_misc_error(tcx).into();
}
tcx.at(self.span).type_of(param.def_id).subst(tcx, substs).into()
} else if infer_args {
self.astconv.ty_infer(Some(param), self.span).into()
} else {
// We've already errored above about the mismatch.
- tcx.ty_error_misc().into()
+ Ty::new_misc_error(tcx).into()
}
}
GenericParamDefKind::Const { has_default } => {
@@ -517,7 +529,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.no_bound_vars()
.expect("const parameter types cannot be generic");
if let Err(guar) = ty.error_reported() {
- return tcx.const_error(ty, guar).into();
+ return ty::Const::new_error(tcx, guar, ty).into();
}
if !infer_args && has_default {
tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
@@ -526,7 +538,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.astconv.ct_infer(ty, Some(param), self.span).into()
} else {
// We've already errored above about the mismatch.
- tcx.const_error_misc(ty).into()
+ ty::Const::new_misc_error(tcx, ty).into()
}
}
}
@@ -884,551 +896,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.is_some()
}
- /// Sets `implicitly_sized` to true on `Bounds` if necessary
- pub(crate) fn add_implicitly_sized(
- &self,
- bounds: &mut Bounds<'tcx>,
- self_ty: Ty<'tcx>,
- ast_bounds: &'tcx [hir::GenericBound<'tcx>],
- self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
- span: Span,
- ) {
- let tcx = self.tcx();
-
- // Try to find an unbound in bounds.
- let mut unbound = None;
- let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
- for ab in ast_bounds {
- if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
- if unbound.is_none() {
- unbound = Some(&ptr.trait_ref);
- } else {
- tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span });
- }
- }
- }
- };
- search_bounds(ast_bounds);
- if let Some((self_ty, where_clause)) = self_ty_where_predicates {
- for clause in where_clause {
- if let hir::WherePredicate::BoundPredicate(pred) = clause {
- if pred.is_param_bound(self_ty.to_def_id()) {
- search_bounds(pred.bounds);
- }
- }
- }
- }
-
- let sized_def_id = tcx.lang_items().sized_trait();
- match (&sized_def_id, unbound) {
- (Some(sized_def_id), Some(tpb))
- if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) =>
- {
- // There was in fact a `?Sized` bound, return without doing anything
- return;
- }
- (_, Some(_)) => {
- // There was a `?Trait` bound, but it was not `?Sized`; warn.
- tcx.sess.span_warn(
- span,
- "default bound relaxed for a type parameter, but \
- this does nothing because the given bound is not \
- a default; only `?Sized` is supported",
- );
- // Otherwise, add implicitly sized if `Sized` is available.
- }
- _ => {
- // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
- }
- }
- if sized_def_id.is_none() {
- // No lang item for `Sized`, so we can't add it as a bound.
- return;
- }
- bounds.push_sized(tcx, self_ty, span);
- }
-
- /// This helper takes a *converted* parameter type (`param_ty`)
- /// and an *unconverted* list of bounds:
- ///
- /// ```text
- /// fn foo<T: Debug>
- /// ^ ^^^^^ `ast_bounds` parameter, in HIR form
- /// |
- /// `param_ty`, in ty form
- /// ```
- ///
- /// It adds these `ast_bounds` into the `bounds` structure.
- ///
- /// **A note on binders:** there is an implied binder around
- /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
- /// for more details.
- #[instrument(level = "debug", skip(self, ast_bounds, bounds))]
- pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>>(
- &self,
- param_ty: Ty<'tcx>,
- ast_bounds: I,
- bounds: &mut Bounds<'tcx>,
- bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
- only_self_bounds: OnlySelfBounds,
- ) {
- for ast_bound in ast_bounds {
- match ast_bound {
- hir::GenericBound::Trait(poly_trait_ref, modifier) => {
- let (constness, polarity) = match modifier {
- hir::TraitBoundModifier::MaybeConst => {
- (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
- }
- hir::TraitBoundModifier::None => {
- (ty::BoundConstness::NotConst, ty::ImplPolarity::Positive)
- }
- hir::TraitBoundModifier::Negative => {
- (ty::BoundConstness::NotConst, ty::ImplPolarity::Negative)
- }
- hir::TraitBoundModifier::Maybe => continue,
- };
- let _ = self.instantiate_poly_trait_ref(
- &poly_trait_ref.trait_ref,
- poly_trait_ref.span,
- constness,
- polarity,
- param_ty,
- bounds,
- false,
- only_self_bounds,
- );
- }
- &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
- self.instantiate_lang_item_trait_ref(
- lang_item,
- span,
- hir_id,
- args,
- param_ty,
- bounds,
- only_self_bounds,
- );
- }
- hir::GenericBound::Outlives(lifetime) => {
- let region = self.ast_region_to_region(lifetime, None);
- bounds.push_region_bound(
- self.tcx(),
- ty::Binder::bind_with_vars(
- ty::OutlivesPredicate(param_ty, region),
- bound_vars,
- ),
- lifetime.ident.span,
- );
- }
- }
- }
- }
-
- /// Translates a list of bounds from the HIR into the `Bounds` data structure.
- /// The self-type for the bounds is given by `param_ty`.
- ///
- /// Example:
- ///
- /// ```ignore (illustrative)
- /// fn foo<T: Bar + Baz>() { }
- /// // ^ ^^^^^^^^^ ast_bounds
- /// // param_ty
- /// ```
- ///
- /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
- /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
- /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
- ///
- /// `span` should be the declaration size of the parameter.
- pub(crate) fn compute_bounds(
- &self,
- param_ty: Ty<'tcx>,
- ast_bounds: &[hir::GenericBound<'_>],
- only_self_bounds: OnlySelfBounds,
- ) -> Bounds<'tcx> {
- let mut bounds = Bounds::default();
- self.add_bounds(
- param_ty,
- ast_bounds.iter(),
- &mut bounds,
- ty::List::empty(),
- only_self_bounds,
- );
- debug!(?bounds);
-
- bounds
- }
-
- /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
- /// named `assoc_name` into ty::Bounds. Ignore the rest.
- pub(crate) fn compute_bounds_that_match_assoc_item(
- &self,
- param_ty: Ty<'tcx>,
- ast_bounds: &[hir::GenericBound<'_>],
- assoc_name: Ident,
- ) -> Bounds<'tcx> {
- let mut result = Vec::new();
-
- for ast_bound in ast_bounds {
- if let Some(trait_ref) = ast_bound.trait_ref()
- && let Some(trait_did) = trait_ref.trait_def_id()
- && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
- {
- result.push(ast_bound.clone());
- }
- }
-
- let mut bounds = Bounds::default();
- self.add_bounds(
- param_ty,
- result.iter(),
- &mut bounds,
- ty::List::empty(),
- OnlySelfBounds(true),
- );
- debug!(?bounds);
-
- bounds
- }
-
- /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates
- /// onto `bounds`.
- ///
- /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
- /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
- /// the binder (e.g., `&'a u32`) and hence may reference bound regions.
- #[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))]
- fn add_predicates_for_ast_type_binding(
- &self,
- hir_ref_id: hir::HirId,
- trait_ref: ty::PolyTraitRef<'tcx>,
- binding: &ConvertedBinding<'_, 'tcx>,
- bounds: &mut Bounds<'tcx>,
- speculative: bool,
- dup_bindings: &mut FxHashMap<DefId, Span>,
- path_span: Span,
- constness: ty::BoundConstness,
- only_self_bounds: OnlySelfBounds,
- polarity: ty::ImplPolarity,
- ) -> Result<(), ErrorGuaranteed> {
- // Given something like `U: SomeTrait<T = X>`, we want to produce a
- // predicate like `<U as SomeTrait>::T = X`. This is somewhat
- // subtle in the event that `T` is defined in a supertrait of
- // `SomeTrait`, because in that case we need to upcast.
- //
- // That is, consider this case:
- //
- // ```
- // trait SubTrait: SuperTrait<i32> { }
- // trait SuperTrait<A> { type T; }
- //
- // ... B: SubTrait<T = foo> ...
- // ```
- //
- // We want to produce `<B as SuperTrait<i32>>::T == foo`.
-
- let tcx = self.tcx();
-
- let return_type_notation =
- binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation;
-
- let candidate = if return_type_notation {
- if self.trait_defines_associated_item_named(
- trait_ref.def_id(),
- ty::AssocKind::Fn,
- binding.item_name,
- ) {
- trait_ref
- } else {
- self.one_bound_for_assoc_method(
- traits::supertraits(tcx, trait_ref),
- trait_ref.print_only_trait_path(),
- binding.item_name,
- path_span,
- )?
- }
- } else if self.trait_defines_associated_item_named(
- trait_ref.def_id(),
- ty::AssocKind::Type,
- binding.item_name,
- ) {
- // Simple case: X is defined in the current trait.
- trait_ref
- } else {
- // Otherwise, we have to walk through the supertraits to find
- // those that do.
- self.one_bound_for_assoc_type(
- || traits::supertraits(tcx, trait_ref),
- trait_ref.skip_binder().print_only_trait_name(),
- binding.item_name,
- path_span,
- match binding.kind {
- ConvertedBindingKind::Equality(term) => Some(term),
- _ => None,
- },
- )?
- };
-
- let (assoc_ident, def_scope) =
- tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
-
- // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
- // of calling `filter_by_name_and_kind`.
- let find_item_of_kind = |kind| {
- tcx.associated_items(candidate.def_id())
- .filter_by_name_unhygienic(assoc_ident.name)
- .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
- };
- let assoc_item = if return_type_notation {
- find_item_of_kind(ty::AssocKind::Fn)
- } else {
- find_item_of_kind(ty::AssocKind::Type)
- .or_else(|| find_item_of_kind(ty::AssocKind::Const))
- }
- .expect("missing associated type");
-
- if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
- tcx.sess
- .struct_span_err(
- binding.span,
- format!("{} `{}` is private", assoc_item.kind, binding.item_name),
- )
- .span_label(binding.span, format!("private {}", assoc_item.kind))
- .emit();
- }
- tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
-
- if !speculative {
- dup_bindings
- .entry(assoc_item.def_id)
- .and_modify(|prev_span| {
- tcx.sess.emit_err(ValueOfAssociatedStructAlreadySpecified {
- span: binding.span,
- prev_span: *prev_span,
- item_name: binding.item_name,
- def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
- });
- })
- .or_insert(binding.span);
- }
-
- let projection_ty = if return_type_notation {
- // If we have an method return type bound, then we need to substitute
- // the method's early bound params with suitable late-bound params.
- let mut num_bound_vars = candidate.bound_vars().len();
- let substs =
- candidate.skip_binder().substs.extend_to(tcx, assoc_item.def_id, |param, _| {
- let subst = match param.kind {
- GenericParamDefKind::Lifetime => tcx
- .mk_re_late_bound(
- ty::INNERMOST,
- ty::BoundRegion {
- var: ty::BoundVar::from_usize(num_bound_vars),
- kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name),
- },
- )
- .into(),
- GenericParamDefKind::Type { .. } => tcx
- .mk_bound(
- ty::INNERMOST,
- ty::BoundTy {
- var: ty::BoundVar::from_usize(num_bound_vars),
- kind: ty::BoundTyKind::Param(param.def_id, param.name),
- },
- )
- .into(),
- GenericParamDefKind::Const { .. } => {
- let ty = tcx
- .type_of(param.def_id)
- .no_bound_vars()
- .expect("ct params cannot have early bound vars");
- tcx.mk_const(
- ty::ConstKind::Bound(
- ty::INNERMOST,
- ty::BoundVar::from_usize(num_bound_vars),
- ),
- ty,
- )
- .into()
- }
- };
- num_bound_vars += 1;
- subst
- });
-
- // Next, we need to check that the return-type notation is being used on
- // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait).
- let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output();
- let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
- && tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
- {
- alias_ty
- } else {
- return Err(self.tcx().sess.emit_err(
- crate::errors::ReturnTypeNotationOnNonRpitit {
- span: binding.span,
- ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
- fn_span: tcx.hir().span_if_local(assoc_item.def_id),
- note: (),
- },
- ));
- };
-
- // Finally, move the fn return type's bound vars over to account for the early bound
- // params (and trait ref's late bound params). This logic is very similar to
- // `Predicate::subst_supertrait`, and it's no coincidence why.
- let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
- let subst_output = ty::EarlyBinder(shifted_output).subst(tcx, substs);
-
- let bound_vars = tcx.late_bound_vars(binding.hir_id);
- ty::Binder::bind_with_vars(subst_output, bound_vars)
- } else {
- // Include substitutions for generic parameters of associated types
- candidate.map_bound(|trait_ref| {
- let ident = Ident::new(assoc_item.name, binding.item_name.span);
- let item_segment = hir::PathSegment {
- ident,
- hir_id: binding.hir_id,
- res: Res::Err,
- args: Some(binding.gen_args),
- infer_args: false,
- };
-
- let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
- path_span,
- assoc_item.def_id,
- &item_segment,
- trait_ref.substs,
- );
-
- debug!(?substs_trait_ref_and_assoc_item);
-
- tcx.mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
- })
- };
-
- if !speculative {
- // Find any late-bound regions declared in `ty` that are not
- // declared in the trait-ref or assoc_item. These are not well-formed.
- //
- // Example:
- //
- // for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
- // for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
- if let ConvertedBindingKind::Equality(ty) = binding.kind {
- let late_bound_in_trait_ref =
- tcx.collect_constrained_late_bound_regions(&projection_ty);
- let late_bound_in_ty =
- tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
- debug!(?late_bound_in_trait_ref);
- debug!(?late_bound_in_ty);
-
- // FIXME: point at the type params that don't have appropriate lifetimes:
- // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
- // ---- ---- ^^^^^^^
- self.validate_late_bound_regions(
- late_bound_in_trait_ref,
- late_bound_in_ty,
- |br_name| {
- struct_span_err!(
- tcx.sess,
- binding.span,
- E0582,
- "binding for associated type `{}` references {}, \
- which does not appear in the trait input types",
- binding.item_name,
- br_name
- )
- },
- );
- }
- }
-
- match binding.kind {
- ConvertedBindingKind::Equality(..) if return_type_notation => {
- return Err(self.tcx().sess.emit_err(
- crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
- ));
- }
- ConvertedBindingKind::Equality(mut term) => {
- // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
- // the "projection predicate" for:
- //
- // `<T as Iterator>::Item = u32`
- let assoc_item_def_id = projection_ty.skip_binder().def_id;
- let def_kind = tcx.def_kind(assoc_item_def_id);
- match (def_kind, term.unpack()) {
- (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_))
- | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (),
- (_, _) => {
- let got = if let Some(_) = term.ty() { "type" } else { "constant" };
- let expected = tcx.def_descr(assoc_item_def_id);
- let mut err = tcx.sess.struct_span_err(
- binding.span,
- format!("expected {expected} bound, found {got}"),
- );
- err.span_note(
- tcx.def_span(assoc_item_def_id),
- format!("{expected} defined here"),
- );
-
- if let hir::def::DefKind::AssocConst = def_kind
- && let Some(t) = term.ty() && (t.is_enum() || t.references_error())
- && tcx.features().associated_const_equality {
- err.span_suggestion(
- binding.span,
- "if equating a const, try wrapping with braces",
- format!("{} = {{ const }}", binding.item_name),
- Applicability::HasPlaceholders,
- );
- }
- let reported = err.emit();
- term = match def_kind {
- hir::def::DefKind::AssocTy => tcx.ty_error(reported).into(),
- hir::def::DefKind::AssocConst => tcx
- .const_error(
- tcx.type_of(assoc_item_def_id)
- .subst(tcx, projection_ty.skip_binder().substs),
- reported,
- )
- .into(),
- _ => unreachable!(),
- };
- }
- }
- bounds.push_projection_bound(
- tcx,
- projection_ty
- .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
- binding.span,
- );
- }
- ConvertedBindingKind::Constraint(ast_bounds) => {
- // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
- //
- // `<T as Iterator>::Item: Debug`
- //
- // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
- // parameter to have a skipped binder.
- //
- // NOTE: If `only_self_bounds` is true, do NOT expand this associated
- // type bound into a trait predicate, since we only want to add predicates
- // for the `Self` type.
- if !only_self_bounds.0 {
- let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder());
- self.add_bounds(
- param_ty,
- ast_bounds.iter(),
- bounds,
- projection_ty.bound_vars(),
- only_self_bounds,
- );
- }
- }
- }
- Ok(())
- }
-
fn ast_path_to_ty(
&self,
span: Span,
@@ -1436,384 +903,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
item_segment: &hir::PathSegment<'_>,
) -> Ty<'tcx> {
let substs = self.ast_path_substs_for_ty(span, did, item_segment);
- self.tcx().at(span).type_of(did).subst(self.tcx(), substs)
- }
-
- fn conv_object_ty_poly_trait_ref(
- &self,
- span: Span,
- hir_trait_bounds: &[hir::PolyTraitRef<'_>],
- lifetime: &hir::Lifetime,
- borrowed: bool,
- representation: DynKind,
- ) -> Ty<'tcx> {
- let tcx = self.tcx();
-
- let mut bounds = Bounds::default();
- let mut potential_assoc_types = Vec::new();
- let dummy_self = self.tcx().types.trait_object_dummy_self;
- for trait_bound in hir_trait_bounds.iter().rev() {
- if let GenericArgCountResult {
- correct:
- Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
- ..
- } = self.instantiate_poly_trait_ref(
- &trait_bound.trait_ref,
- trait_bound.span,
- ty::BoundConstness::NotConst,
- ty::ImplPolarity::Positive,
- dummy_self,
- &mut bounds,
- false,
- // FIXME: This should be `true`, but we don't really handle
- // associated type bounds or type aliases in objects in a way
- // that makes this meaningful, I think.
- OnlySelfBounds(false),
- ) {
- potential_assoc_types.extend(cur_potential_assoc_types);
- }
- }
-
- let mut trait_bounds = vec![];
- let mut projection_bounds = vec![];
- for (pred, span) in bounds.predicates() {
- let bound_pred = pred.kind();
- match bound_pred.skip_binder() {
- ty::PredicateKind::Clause(clause) => match clause {
- ty::Clause::Trait(trait_pred) => {
- assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
- trait_bounds.push((
- bound_pred.rebind(trait_pred.trait_ref),
- span,
- trait_pred.constness,
- ));
- }
- ty::Clause::Projection(proj) => {
- projection_bounds.push((bound_pred.rebind(proj), span));
- }
- ty::Clause::TypeOutlives(_) => {
- // Do nothing, we deal with regions separately
- }
- ty::Clause::RegionOutlives(_) | ty::Clause::ConstArgHasType(..) => bug!(),
- },
- ty::PredicateKind::WellFormed(_)
- | ty::PredicateKind::AliasRelate(..)
- | ty::PredicateKind::ObjectSafe(_)
- | ty::PredicateKind::ClosureKind(_, _, _)
- | ty::PredicateKind::Subtype(_)
- | ty::PredicateKind::Coerce(_)
- | ty::PredicateKind::ConstEvaluatable(_)
- | ty::PredicateKind::ConstEquate(_, _)
- | ty::PredicateKind::TypeWellFormedFromEnv(_)
- | ty::PredicateKind::Ambiguous => bug!(),
- }
- }
-
- // Expand trait aliases recursively and check that only one regular (non-auto) trait
- // is used and no 'maybe' bounds are used.
- let expanded_traits =
- traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b)));
-
- let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
- .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
- .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
- if regular_traits.len() > 1 {
- let first_trait = &regular_traits[0];
- let additional_trait = &regular_traits[1];
- let mut err = struct_span_err!(
- tcx.sess,
- additional_trait.bottom().1,
- E0225,
- "only auto traits can be used as additional traits in a trait object"
- );
- additional_trait.label_with_exp_info(
- &mut err,
- "additional non-auto trait",
- "additional use",
- );
- first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
- err.help(format!(
- "consider creating a new trait with all of these as supertraits and using that \
- trait here instead: `trait NewTrait: {} {{}}`",
- regular_traits
- .iter()
- .map(|t| t.trait_ref().print_only_trait_path().to_string())
- .collect::<Vec<_>>()
- .join(" + "),
- ));
- err.note(
- "auto-traits like `Send` and `Sync` are traits that have special properties; \
- for more information on them, visit \
- <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
- );
- err.emit();
- }
-
- if regular_traits.is_empty() && auto_traits.is_empty() {
- let trait_alias_span = trait_bounds
- .iter()
- .map(|&(trait_ref, _, _)| trait_ref.def_id())
- .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
- .map(|trait_ref| tcx.def_span(trait_ref));
- let reported =
- tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
- return tcx.ty_error(reported);
- }
-
- // Check that there are no gross object safety violations;
- // most importantly, that the supertraits don't contain `Self`,
- // to avoid ICEs.
- for item in &regular_traits {
- let object_safety_violations =
- astconv_object_safety_violations(tcx, item.trait_ref().def_id());
- if !object_safety_violations.is_empty() {
- let reported = report_object_safety_error(
- tcx,
- span,
- item.trait_ref().def_id(),
- &object_safety_violations,
- )
- .emit();
- return tcx.ty_error(reported);
- }
- }
-
- // Use a `BTreeSet` to keep output in a more consistent order.
- let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default();
-
- let regular_traits_refs_spans = trait_bounds
- .into_iter()
- .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
-
- for (base_trait_ref, span, constness) in regular_traits_refs_spans {
- assert_eq!(constness, ty::BoundConstness::NotConst);
- let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx);
- for pred in traits::elaborate(tcx, [base_pred]) {
- debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred);
-
- let bound_predicate = pred.kind();
- match bound_predicate.skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
- let pred = bound_predicate.rebind(pred);
- associated_types.entry(span).or_default().extend(
- tcx.associated_items(pred.def_id())
- .in_definition_order()
- .filter(|item| item.kind == ty::AssocKind::Type)
- .filter(|item| tcx.opt_rpitit_info(item.def_id).is_none())
- .map(|item| item.def_id),
- );
- }
- ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
- let pred = bound_predicate.rebind(pred);
- // A `Self` within the original bound will be substituted with a
- // `trait_object_dummy_self`, so check for that.
- let references_self = match pred.skip_binder().term.unpack() {
- ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
- ty::TermKind::Const(c) => {
- c.ty().walk().any(|arg| arg == dummy_self.into())
- }
- };
-
- // If the projection output contains `Self`, force the user to
- // elaborate it explicitly to avoid a lot of complexity.
- //
- // The "classically useful" case is the following:
- // ```
- // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput {
- // type MyOutput;
- // }
- // ```
- //
- // Here, the user could theoretically write `dyn MyTrait<Output = X>`,
- // but actually supporting that would "expand" to an infinitely-long type
- // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
- //
- // Instead, we force the user to write
- // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
- // the discussion in #56288 for alternatives.
- if !references_self {
- // Include projections defined on supertraits.
- projection_bounds.push((pred, span));
- }
- }
- _ => (),
- }
- }
- }
-
- for (projection_bound, _) in &projection_bounds {
- for def_ids in associated_types.values_mut() {
- def_ids.remove(&projection_bound.projection_def_id());
- }
- }
-
- self.complain_about_missing_associated_types(
- associated_types,
- potential_assoc_types,
- hir_trait_bounds,
- );
-
- // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
- // `dyn Trait + Send`.
- // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
- // the bounds
- let mut duplicates = FxHashSet::default();
- auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id()));
- debug!("regular_traits: {:?}", regular_traits);
- debug!("auto_traits: {:?}", auto_traits);
-
- // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
- let existential_trait_refs = regular_traits.iter().map(|i| {
- i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
- assert_eq!(trait_ref.self_ty(), dummy_self);
-
- // Verify that `dummy_self` did not leak inside default type parameters. This
- // could not be done at path creation, since we need to see through trait aliases.
- let mut missing_type_params = vec![];
- let mut references_self = false;
- let generics = tcx.generics_of(trait_ref.def_id);
- let substs: Vec<_> = trait_ref
- .substs
- .iter()
- .enumerate()
- .skip(1) // Remove `Self` for `ExistentialPredicate`.
- .map(|(index, arg)| {
- if arg == dummy_self.into() {
- let param = &generics.params[index];
- missing_type_params.push(param.name);
- return tcx.ty_error_misc().into();
- } else if arg.walk().any(|arg| arg == dummy_self.into()) {
- references_self = true;
- return tcx.ty_error_misc().into();
- }
- arg
- })
- .collect();
- let substs = tcx.mk_substs(&substs);
-
- let span = i.bottom().1;
- let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
- hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
- && hir_bound.span.contains(span)
- });
- self.complain_about_missing_type_params(
- missing_type_params,
- trait_ref.def_id,
- span,
- empty_generic_args,
- );
+ let ty = self.tcx().at(span).type_of(did);
- if references_self {
- let def_id = i.bottom().0.def_id();
- let mut err = struct_span_err!(
- tcx.sess,
- i.bottom().1,
- E0038,
- "the {} `{}` cannot be made into an object",
- tcx.def_descr(def_id),
- tcx.item_name(def_id),
- );
- err.note(
- rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![])
- .error_msg(),
- );
- err.emit();
- }
-
- ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs }
- })
- });
-
- let existential_projections = projection_bounds
- .iter()
- // We filter out traits that don't have `Self` as their self type above,
- // we need to do the same for projections.
- .filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self)
- .map(|(bound, _)| {
- bound.map_bound(|mut b| {
- assert_eq!(b.projection_ty.self_ty(), dummy_self);
-
- // Like for trait refs, verify that `dummy_self` did not leak inside default type
- // parameters.
- let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| {
- if arg.walk().any(|arg| arg == dummy_self.into()) {
- return true;
- }
- false
- });
- if references_self {
- let guar = tcx.sess.delay_span_bug(
- span,
- "trait object projection bounds reference `Self`",
- );
- let substs: Vec<_> = b
- .projection_ty
- .substs
- .iter()
- .map(|arg| {
- if arg.walk().any(|arg| arg == dummy_self.into()) {
- return tcx.ty_error(guar).into();
- }
- arg
- })
- .collect();
- b.projection_ty.substs = tcx.mk_substs(&substs);
- }
-
- ty::ExistentialProjection::erase_self_ty(tcx, b)
- })
- });
-
- let regular_trait_predicates = existential_trait_refs
- .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));
- let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| {
- ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()))
- });
- // N.b. principal, projections, auto traits
- // FIXME: This is actually wrong with multiple principals in regards to symbol mangling
- let mut v = regular_trait_predicates
- .chain(
- existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)),
- )
- .chain(auto_trait_predicates)
- .collect::<SmallVec<[_; 8]>>();
- v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
- v.dedup();
- let existential_predicates = tcx.mk_poly_existential_predicates(&v);
-
- // Use explicitly-specified region bound.
- let region_bound = if !lifetime.is_elided() {
- self.ast_region_to_region(lifetime, None)
+ if matches!(self.tcx().def_kind(did), DefKind::TyAlias)
+ && (ty.skip_binder().has_opaque_types() || self.tcx().features().lazy_type_alias)
+ {
+ // Type aliases referring to types that contain opaque types (but aren't just directly
+ // referencing a single opaque type) get encoded as a type alias that normalization will
+ // then actually instantiate the where bounds of.
+ let alias_ty = self.tcx().mk_alias_ty(did, substs);
+ Ty::new_alias(self.tcx(), ty::Weak, alias_ty)
} else {
- self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
- if tcx.named_bound_var(lifetime.hir_id).is_some() {
- self.ast_region_to_region(lifetime, None)
- } else {
- self.re_infer(None, span).unwrap_or_else(|| {
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0228,
- "the lifetime bound for this object type cannot be deduced \
- from context; please supply an explicit bound"
- );
- let e = if borrowed {
- // We will have already emitted an error E0106 complaining about a
- // missing named lifetime in `&dyn Trait`, so we elide this one.
- err.delay_as_bug()
- } else {
- err.emit()
- };
- tcx.mk_re_error(e)
- })
- }
- })
- };
- debug!("region_bound: {:?}", region_bound);
-
- let ty = tcx.mk_dynamic(existential_predicates, region_bound, representation);
- debug!("trait_object_type: {:?}", ty);
- ty
+ ty.subst(self.tcx(), substs)
+ }
}
fn report_ambiguous_associated_type(
@@ -1948,9 +1050,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|| {
traits::transitive_bounds_that_define_assoc_item(
tcx,
- predicates.iter().filter_map(|(p, _)| {
- Some(p.to_opt_poly_trait_pred()?.map_bound(|t| t.trait_ref))
- }),
+ predicates
+ .iter()
+ .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))),
assoc_name,
)
},
@@ -2408,6 +1510,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) -> Result<Option<(Ty<'tcx>, DefId)>, ErrorGuaranteed> {
let tcx = self.tcx();
+ // Don't attempt to look up inherent associated types when the feature is not enabled.
+ // Theoretically it'd be fine to do so since we feature-gate their definition site.
+ // However, due to current limitations of the implementation (caused by us performing
+ // selection in AstConv), IATs can lead to cycle errors (#108491, #110106) which mask the
+ // feature-gate error, needlessly confusing users that use IATs by accident (#113265).
+ if !tcx.features().inherent_associated_types {
+ return Ok(None);
+ }
+
let candidates: Vec<_> = tcx
.inherent_impls(adt_did)
.iter()
@@ -2441,32 +1552,64 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut fulfillment_errors = Vec::new();
let mut applicable_candidates: Vec<_> = infcx.probe(|_| {
- let universe = infcx.create_next_universe();
-
// Regions are not considered during selection.
- // FIXME(non_lifetime_binders): Here we are "truncating" or "flattening" the universes
- // of type and const binders. Is that correct in the selection phase? See also #109505.
- let self_ty = tcx.replace_escaping_bound_vars_uncached(
- self_ty,
- FnMutDelegate {
- regions: &mut |_| tcx.lifetimes.re_erased,
- types: &mut |bv| {
- tcx.mk_placeholder(ty::PlaceholderType { universe, bound: bv })
- },
- consts: &mut |bv, ty| {
- tcx.mk_const(ty::PlaceholderConst { universe, bound: bv }, ty)
- },
- },
- );
+ let self_ty = self_ty
+ .fold_with(&mut BoundVarEraser { tcx, universe: infcx.create_next_universe() });
+
+ struct BoundVarEraser<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ universe: ty::UniverseIndex,
+ }
+
+ // FIXME(non_lifetime_binders): Don't assign the same universe to each placeholder.
+ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarEraser<'tcx> {
+ fn interner(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ if r.is_late_bound() { self.tcx.lifetimes.re_erased } else { r }
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ match *ty.kind() {
+ ty::Bound(_, bv) => Ty::new_placeholder(
+ self.tcx,
+ ty::PlaceholderType { universe: self.universe, bound: bv },
+ ),
+ _ => ty.super_fold_with(self),
+ }
+ }
+
+ fn fold_const(
+ &mut self,
+ ct: ty::Const<'tcx>,
+ ) -> <TyCtxt<'tcx> as rustc_type_ir::Interner>::Const {
+ assert!(!ct.ty().has_escaping_bound_vars());
+
+ match ct.kind() {
+ ty::ConstKind::Bound(_, bv) => ty::Const::new_placeholder(
+ self.tcx,
+ ty::PlaceholderConst { universe: self.universe, bound: bv },
+ ct.ty(),
+ ),
+ _ => ct.super_fold_with(self),
+ }
+ }
+ }
+
+ let InferOk { value: self_ty, obligations } =
+ infcx.at(&cause, param_env).normalize(self_ty);
candidates
.iter()
.copied()
.filter(|&(impl_, _)| {
infcx.probe(|_| {
- let ocx = ObligationCtxt::new_in_snapshot(&infcx);
+ let ocx = ObligationCtxt::new(&infcx);
+ ocx.register_obligations(obligations.clone());
- let impl_substs = infcx.fresh_item_substs(impl_);
+ let impl_substs = infcx.fresh_substs_for_item(span, impl_);
let impl_ty = tcx.type_of(impl_).subst(tcx, impl_substs);
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
@@ -2522,7 +1665,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.chain(substs.into_iter().skip(parent_substs.len())),
);
- let ty = tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(assoc_item, substs));
+ let ty = Ty::new_alias(tcx, ty::Inherent, tcx.mk_alias_ty(assoc_item, substs));
return Ok(Some((ty, assoc_item)));
}
@@ -2707,7 +1850,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&[path_str],
item_segment.ident.name,
);
- return tcx.ty_error(reported)
+ return Ty::new_error(tcx,reported)
};
debug!("qpath_to_ty: self_type={:?}", self_ty);
@@ -2730,7 +1873,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
- tcx.mk_projection(item_def_id, item_substs)
+ Ty::new_projection(tcx, item_def_id, item_substs)
}
pub fn prohibit_generics<'a>(
@@ -2993,7 +2136,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.note("`impl Trait` types can't have type parameters");
});
let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
- tcx.mk_opaque(did, substs)
+ Ty::new_opaque(tcx, did, substs)
}
Res::Def(
DefKind::Enum
@@ -3045,16 +2188,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
var: ty::BoundVar::from_u32(index),
kind: ty::BoundTyKind::Param(def_id, name),
};
- tcx.mk_bound(debruijn, br)
+ Ty::new_bound(tcx, debruijn, br)
}
Some(rbv::ResolvedArg::EarlyBound(_)) => {
let def_id = def_id.expect_local();
let item_def_id = tcx.hir().ty_param_owner(def_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
- tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
+ Ty::new_param(tcx, index, tcx.hir().ty_param_name(def_id))
}
- Some(rbv::ResolvedArg::Error(guar)) => tcx.ty_error(guar),
+ Some(rbv::ResolvedArg::Error(guar)) => Ty::new_error(tcx, guar),
arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
}
}
@@ -3166,7 +2309,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
{
err.span_note(impl_.self_ty.span, "not a concrete type");
}
- tcx.ty_error(err.emit())
+ Ty::new_error(tcx, err.emit())
} else {
ty
}
@@ -3207,9 +2350,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
match prim_ty {
hir::PrimTy::Bool => tcx.types.bool,
hir::PrimTy::Char => tcx.types.char,
- hir::PrimTy::Int(it) => tcx.mk_mach_int(ty::int_ty(it)),
- hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(ty::uint_ty(uit)),
- hir::PrimTy::Float(ft) => tcx.mk_mach_float(ty::float_ty(ft)),
+ hir::PrimTy::Int(it) => Ty::new_int(tcx, ty::int_ty(it)),
+ hir::PrimTy::Uint(uit) => Ty::new_uint(tcx, ty::uint_ty(uit)),
+ hir::PrimTy::Float(ft) => Ty::new_float(tcx, ty::float_ty(ft)),
hir::PrimTy::Str => tcx.types.str_,
}
}
@@ -3219,7 +2362,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.sess
.delay_span_bug(path.span, "path with `Res::Err` but no error emitted");
self.set_tainted_by_errors(e);
- self.tcx().ty_error(e)
+ Ty::new_error(self.tcx(), e)
}
_ => span_bug!(span, "unexpected resolution: {:?}", path.res),
}
@@ -3244,31 +2387,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let tcx = self.tcx();
let result_ty = match &ast_ty.kind {
- hir::TyKind::Slice(ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)),
+ hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.ast_ty_to_ty(ty)),
hir::TyKind::Ptr(mt) => {
- tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
+ Ty::new_ptr(tcx, ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
}
hir::TyKind::Ref(region, mt) => {
let r = self.ast_region_to_region(region, None);
debug!(?r);
let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
- tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
+ Ty::new_ref(tcx, r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
}
hir::TyKind::Never => tcx.types.never,
hir::TyKind::Tup(fields) => {
- tcx.mk_tup_from_iter(fields.iter().map(|t| self.ast_ty_to_ty(t)))
+ Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t)))
}
hir::TyKind::BareFn(bf) => {
require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
- tcx.mk_fn_ptr(self.ty_of_fn(
- ast_ty.hir_id,
- bf.unsafety,
- bf.abi,
- bf.decl,
- None,
- Some(ast_ty),
- ))
+ Ty::new_fn_ptr(
+ tcx,
+ self.ty_of_fn(ast_ty.hir_id, bf.unsafety, bf.abi, bf.decl, None, Some(ast_ty)),
+ )
}
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
self.maybe_lint_bare_trait(ast_ty, in_path);
@@ -3277,7 +2416,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
TraitObjectSyntax::DynStar => ty::DynStar,
};
- self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr)
+ self.conv_object_ty_poly_trait_ref(
+ ast_ty.span,
+ ast_ty.hir_id,
+ bounds,
+ lifetime,
+ borrowed,
+ repr,
+ )
}
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
debug!(?maybe_qself, ?path);
@@ -3288,7 +2434,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let opaque_ty = tcx.hir().item(item_id);
match opaque_ty.kind {
- hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
+ hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin, .. }) => {
let local_def_id = item_id.owner_id.def_id;
// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
// generate the def_id of an associated type for the trait and return as
@@ -3308,7 +2454,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let ty = self.ast_ty_to_ty_inner(qself, false, true);
self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
.map(|(ty, _, _)| ty)
- .unwrap_or_else(|guar| tcx.ty_error(guar))
+ .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
}
&hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => {
let def_id = tcx.require_lang_item(lang_item, Some(span));
@@ -3332,7 +2478,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
};
- tcx.mk_array_with_const_len(self.ast_ty_to_ty(ty), length)
+ Ty::new_array_with_const_len(tcx, self.ast_ty_to_ty(ty), length)
}
hir::TyKind::Typeof(e) => {
let ty_erased = tcx.type_of(e.def_id).subst_identity();
@@ -3356,7 +2502,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// handled specially and will not descend into this routine.
self.ty_infer(None, ast_ty.span)
}
- hir::TyKind::Err(guar) => tcx.ty_error(*guar),
+ hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar),
};
self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
@@ -3393,7 +2539,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
});
debug!("impl_trait_ty_to_ty: substs={:?}", substs);
- if in_trait { tcx.mk_projection(def_id, substs) } else { tcx.mk_opaque(def_id, substs) }
+ if in_trait {
+ Ty::new_projection(tcx, def_id, substs)
+ } else {
+ Ty::new_opaque(tcx, def_id, substs)
+ }
}
pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
@@ -3462,7 +2612,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.ast_ty_to_ty(output)
}
}
- hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
+ hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx,),
};
debug!(?output_ty);
@@ -3641,148 +2791,4 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
Some(r)
}
-
- /// Make sure that we are in the condition to suggest the blanket implementation.
- fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) {
- 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: Some(of_trait_ref), generics, ..
- }),
- ..
- }) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
- {
- if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
- return;
- }
- let of_trait_span = of_trait_ref.path.span;
- // make sure that we are not calling unwrap to abort during the compilation
- let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; };
- let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; };
- // 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))
- };
- diag.multipart_suggestion(
- format!("alternatively use a blanket \
- implementation to implement `{of_trait_name}` for \
- all types that also implement `{impl_trait_name}`"),
- vec![
- (self_ty.span, param_name),
- add_generic_sugg,
- ],
- Applicability::MaybeIncorrect,
- );
- }
- }
-
- fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
- let tcx = self.tcx();
- if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
- self_ty.kind
- {
- 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::from_iter([(
- 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().rust_2021() {
- let msg = "trait objects must include the `dyn` keyword";
- let label = "add `dyn` keyword before this trait";
- let mut diag =
- rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
- if self_ty.span.can_be_used_for_suggestions() {
- diag.multipart_suggestion_verbose(
- label,
- sugg,
- Applicability::MachineApplicable,
- );
- }
- // check if the impl trait that we are considering is a impl of a local trait
- self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
- diag.stash(self_ty.span, StashKey::TraitMissingMethod);
- } else {
- let msg = "trait objects without an explicit `dyn` are deprecated";
- tcx.struct_span_lint_hir(
- BARE_TRAIT_OBJECTS,
- self_ty.hir_id,
- self_ty.span,
- msg,
- |lint| {
- lint.multipart_suggestion_verbose(
- "use `dyn`",
- sugg,
- Applicability::MachineApplicable,
- );
- self.maybe_lint_blanket_trait_impl(&self_ty, lint);
- lint
- },
- );
- }
- }
- }
-}
-
-pub trait InferCtxtExt<'tcx> {
- fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx>;
-}
-
-impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
- fn fresh_item_substs(&self, def_id: DefId) -> SubstsRef<'tcx> {
- InternalSubsts::for_item(self.tcx, def_id, |param, _| match param.kind {
- GenericParamDefKind::Lifetime => self.tcx.lifetimes.re_erased.into(),
- GenericParamDefKind::Type { .. } => self
- .next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::SubstitutionPlaceholder,
- span: self.tcx.def_span(def_id),
- })
- .into(),
- GenericParamDefKind::Const { .. } => {
- let span = self.tcx.def_span(def_id);
- let origin = ConstVariableOrigin {
- kind: ConstVariableOriginKind::SubstitutionPlaceholder,
- span,
- };
- self.next_const_var(
- self.tcx
- .type_of(param.def_id)
- .no_bound_vars()
- .expect("const parameter types cannot be generic"),
- origin,
- )
- .into()
- }
- })
- }
}
diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
new file mode 100644
index 000000000..9227ee934
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
@@ -0,0 +1,408 @@
+use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
+use crate::bounds::Bounds;
+use crate::errors::TraitObjectDeclaredWithNoTraits;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
+use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{DynKind, ToPredicate};
+use rustc_span::Span;
+use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
+use rustc_trait_selection::traits::{self, astconv_object_safety_violations};
+
+use smallvec::{smallvec, SmallVec};
+use std::collections::BTreeSet;
+
+use super::AstConv;
+
+impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
+ pub(super) fn conv_object_ty_poly_trait_ref(
+ &self,
+ span: Span,
+ hir_id: hir::HirId,
+ hir_trait_bounds: &[hir::PolyTraitRef<'_>],
+ lifetime: &hir::Lifetime,
+ borrowed: bool,
+ representation: DynKind,
+ ) -> Ty<'tcx> {
+ let tcx = self.tcx();
+
+ let mut bounds = Bounds::default();
+ let mut potential_assoc_types = Vec::new();
+ let dummy_self = self.tcx().types.trait_object_dummy_self;
+ for trait_bound in hir_trait_bounds.iter().rev() {
+ if let GenericArgCountResult {
+ correct:
+ Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
+ ..
+ } = self.instantiate_poly_trait_ref(
+ &trait_bound.trait_ref,
+ trait_bound.span,
+ ty::BoundConstness::NotConst,
+ ty::ImplPolarity::Positive,
+ dummy_self,
+ &mut bounds,
+ false,
+ // FIXME: This should be `true`, but we don't really handle
+ // associated type bounds or type aliases in objects in a way
+ // that makes this meaningful, I think.
+ OnlySelfBounds(false),
+ ) {
+ potential_assoc_types.extend(cur_potential_assoc_types);
+ }
+ }
+
+ let mut trait_bounds = vec![];
+ let mut projection_bounds = vec![];
+ for (pred, span) in bounds.clauses() {
+ let bound_pred = pred.kind();
+ match bound_pred.skip_binder() {
+ ty::ClauseKind::Trait(trait_pred) => {
+ assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
+ trait_bounds.push((
+ bound_pred.rebind(trait_pred.trait_ref),
+ span,
+ trait_pred.constness,
+ ));
+ }
+ ty::ClauseKind::Projection(proj) => {
+ projection_bounds.push((bound_pred.rebind(proj), span));
+ }
+ ty::ClauseKind::TypeOutlives(_) => {
+ // Do nothing, we deal with regions separately
+ }
+ ty::ClauseKind::RegionOutlives(_)
+ | ty::ClauseKind::ConstArgHasType(..)
+ | ty::ClauseKind::WellFormed(_)
+ | ty::ClauseKind::ConstEvaluatable(_) => {
+ bug!()
+ }
+ }
+ }
+
+ // Expand trait aliases recursively and check that only one regular (non-auto) trait
+ // is used and no 'maybe' bounds are used.
+ let expanded_traits =
+ traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b, _)| (a, b)));
+
+ let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = expanded_traits
+ .filter(|i| i.trait_ref().self_ty().skip_binder() == dummy_self)
+ .partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
+ if regular_traits.len() > 1 {
+ let first_trait = &regular_traits[0];
+ let additional_trait = &regular_traits[1];
+ let mut err = struct_span_err!(
+ tcx.sess,
+ additional_trait.bottom().1,
+ E0225,
+ "only auto traits can be used as additional traits in a trait object"
+ );
+ additional_trait.label_with_exp_info(
+ &mut err,
+ "additional non-auto trait",
+ "additional use",
+ );
+ first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
+ err.help(format!(
+ "consider creating a new trait with all of these as supertraits and using that \
+ trait here instead: `trait NewTrait: {} {{}}`",
+ regular_traits
+ .iter()
+ .map(|t| t.trait_ref().print_only_trait_path().to_string())
+ .collect::<Vec<_>>()
+ .join(" + "),
+ ));
+ err.note(
+ "auto-traits like `Send` and `Sync` are traits that have special properties; \
+ for more information on them, visit \
+ <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
+ );
+ err.emit();
+ }
+
+ if regular_traits.is_empty() && auto_traits.is_empty() {
+ let trait_alias_span = trait_bounds
+ .iter()
+ .map(|&(trait_ref, _, _)| trait_ref.def_id())
+ .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
+ .map(|trait_ref| tcx.def_span(trait_ref));
+ let reported =
+ tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
+ return Ty::new_error(tcx, reported);
+ }
+
+ // Check that there are no gross object safety violations;
+ // most importantly, that the supertraits don't contain `Self`,
+ // to avoid ICEs.
+ for item in &regular_traits {
+ let object_safety_violations =
+ astconv_object_safety_violations(tcx, item.trait_ref().def_id());
+ if !object_safety_violations.is_empty() {
+ let reported = report_object_safety_error(
+ tcx,
+ span,
+ item.trait_ref().def_id(),
+ &object_safety_violations,
+ )
+ .emit();
+ return Ty::new_error(tcx, reported);
+ }
+ }
+
+ // Use a `BTreeSet` to keep output in a more consistent order.
+ let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default();
+
+ let regular_traits_refs_spans = trait_bounds
+ .into_iter()
+ .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
+
+ for (base_trait_ref, span, constness) in regular_traits_refs_spans {
+ assert_eq!(constness, ty::BoundConstness::NotConst);
+ let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx);
+ for pred in traits::elaborate(tcx, [base_pred]) {
+ debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred);
+
+ let bound_predicate = pred.kind();
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
+ let pred = bound_predicate.rebind(pred);
+ associated_types.entry(span).or_default().extend(
+ tcx.associated_items(pred.def_id())
+ .in_definition_order()
+ .filter(|item| item.kind == ty::AssocKind::Type)
+ .filter(|item| item.opt_rpitit_info.is_none())
+ .map(|item| item.def_id),
+ );
+ }
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
+ let pred = bound_predicate.rebind(pred);
+ // A `Self` within the original bound will be substituted with a
+ // `trait_object_dummy_self`, so check for that.
+ let references_self = match pred.skip_binder().term.unpack() {
+ ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
+ ty::TermKind::Const(c) => {
+ c.ty().walk().any(|arg| arg == dummy_self.into())
+ }
+ };
+
+ // If the projection output contains `Self`, force the user to
+ // elaborate it explicitly to avoid a lot of complexity.
+ //
+ // The "classically useful" case is the following:
+ // ```
+ // trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput {
+ // type MyOutput;
+ // }
+ // ```
+ //
+ // Here, the user could theoretically write `dyn MyTrait<Output = X>`,
+ // but actually supporting that would "expand" to an infinitely-long type
+ // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
+ //
+ // Instead, we force the user to write
+ // `dyn MyTrait<MyOutput = X, Output = X>`, which is uglier but works. See
+ // the discussion in #56288 for alternatives.
+ if !references_self {
+ // Include projections defined on supertraits.
+ projection_bounds.push((pred, span));
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+
+ // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`.
+ // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
+ // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
+ // corresponding `Projection` clause
+ for def_ids in associated_types.values_mut() {
+ for (projection_bound, span) in &projection_bounds {
+ let def_id = projection_bound.projection_def_id();
+ def_ids.remove(&def_id);
+ if tcx.generics_require_sized_self(def_id) {
+ tcx.emit_spanned_lint(
+ UNUSED_ASSOCIATED_TYPE_BOUNDS,
+ hir_id,
+ *span,
+ crate::errors::UnusedAssociatedTypeBounds { span: *span },
+ );
+ }
+ }
+ // If the associated type has a `where Self: Sized` bound, we do not need to constrain the associated
+ // type in the `dyn Trait`.
+ def_ids.retain(|def_id| !tcx.generics_require_sized_self(def_id));
+ }
+
+ self.complain_about_missing_associated_types(
+ associated_types,
+ potential_assoc_types,
+ hir_trait_bounds,
+ );
+
+ // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
+ // `dyn Trait + Send`.
+ // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
+ // the bounds
+ let mut duplicates = FxHashSet::default();
+ auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id()));
+ debug!("regular_traits: {:?}", regular_traits);
+ debug!("auto_traits: {:?}", auto_traits);
+
+ // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
+ let existential_trait_refs = regular_traits.iter().map(|i| {
+ i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
+ assert_eq!(trait_ref.self_ty(), dummy_self);
+
+ // Verify that `dummy_self` did not leak inside default type parameters. This
+ // could not be done at path creation, since we need to see through trait aliases.
+ let mut missing_type_params = vec![];
+ let mut references_self = false;
+ let generics = tcx.generics_of(trait_ref.def_id);
+ let substs: Vec<_> = trait_ref
+ .substs
+ .iter()
+ .enumerate()
+ .skip(1) // Remove `Self` for `ExistentialPredicate`.
+ .map(|(index, arg)| {
+ if arg == dummy_self.into() {
+ let param = &generics.params[index];
+ missing_type_params.push(param.name);
+ return Ty::new_misc_error(tcx).into();
+ } else if arg.walk().any(|arg| arg == dummy_self.into()) {
+ references_self = true;
+ return Ty::new_misc_error(tcx).into();
+ }
+ arg
+ })
+ .collect();
+ let substs = tcx.mk_substs(&substs);
+
+ let span = i.bottom().1;
+ let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
+ hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
+ && hir_bound.span.contains(span)
+ });
+ self.complain_about_missing_type_params(
+ missing_type_params,
+ trait_ref.def_id,
+ span,
+ empty_generic_args,
+ );
+
+ if references_self {
+ let def_id = i.bottom().0.def_id();
+ let mut err = struct_span_err!(
+ tcx.sess,
+ i.bottom().1,
+ E0038,
+ "the {} `{}` cannot be made into an object",
+ tcx.def_descr(def_id),
+ tcx.item_name(def_id),
+ );
+ err.note(
+ rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![])
+ .error_msg(),
+ );
+ err.emit();
+ }
+
+ ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs }
+ })
+ });
+
+ let existential_projections = projection_bounds
+ .iter()
+ // We filter out traits that don't have `Self` as their self type above,
+ // we need to do the same for projections.
+ .filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self)
+ .map(|(bound, _)| {
+ bound.map_bound(|mut b| {
+ assert_eq!(b.projection_ty.self_ty(), dummy_self);
+
+ // Like for trait refs, verify that `dummy_self` did not leak inside default type
+ // parameters.
+ let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| {
+ if arg.walk().any(|arg| arg == dummy_self.into()) {
+ return true;
+ }
+ false
+ });
+ if references_self {
+ let guar = tcx.sess.delay_span_bug(
+ span,
+ "trait object projection bounds reference `Self`",
+ );
+ let substs: Vec<_> = b
+ .projection_ty
+ .substs
+ .iter()
+ .map(|arg| {
+ if arg.walk().any(|arg| arg == dummy_self.into()) {
+ return Ty::new_error(tcx, guar).into();
+ }
+ arg
+ })
+ .collect();
+ b.projection_ty.substs = tcx.mk_substs(&substs);
+ }
+
+ ty::ExistentialProjection::erase_self_ty(tcx, b)
+ })
+ });
+
+ let regular_trait_predicates = existential_trait_refs
+ .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));
+ let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| {
+ ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()))
+ });
+ // N.b. principal, projections, auto traits
+ // FIXME: This is actually wrong with multiple principals in regards to symbol mangling
+ let mut v = regular_trait_predicates
+ .chain(
+ existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)),
+ )
+ .chain(auto_trait_predicates)
+ .collect::<SmallVec<[_; 8]>>();
+ v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
+ v.dedup();
+ let existential_predicates = tcx.mk_poly_existential_predicates(&v);
+
+ // Use explicitly-specified region bound.
+ let region_bound = if !lifetime.is_elided() {
+ self.ast_region_to_region(lifetime, None)
+ } else {
+ self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
+ if tcx.named_bound_var(lifetime.hir_id).is_some() {
+ self.ast_region_to_region(lifetime, None)
+ } else {
+ self.re_infer(None, span).unwrap_or_else(|| {
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0228,
+ "the lifetime bound for this object type cannot be deduced \
+ from context; please supply an explicit bound"
+ );
+ let e = if borrowed {
+ // We will have already emitted an error E0106 complaining about a
+ // missing named lifetime in `&dyn Trait`, so we elide this one.
+ err.delay_as_bug()
+ } else {
+ err.emit()
+ };
+ ty::Region::new_error(tcx, e)
+ })
+ }
+ })
+ };
+ debug!("region_bound: {:?}", region_bound);
+
+ let ty = Ty::new_dynamic(tcx, existential_predicates, region_bound, representation);
+ debug!("trait_object_type: {:?}", ty);
+ ty
+ }
+}