blob: 297cfe7027ec5bca5d3e4276bc0e4d9312e17df0 [file] [log] [blame]
use crate::bounds::Bounds;
use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::{codes::*, struct_span_code_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::fold::BottomUpFolder;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{DynKind, ToPredicate};
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
use smallvec::{smallvec, SmallVec};
use super::HirTyLowerer;
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// Lower a trait object type from the HIR to our internal notion of a type.
#[instrument(level = "debug", skip_all, ret)]
pub(super) fn lower_trait_object_ty(
&self,
span: Span,
hir_id: hir::HirId,
hir_trait_bounds: &[hir::PolyTraitRef<'tcx>],
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.lower_poly_trait_ref(
&trait_bound.trait_ref,
trait_bound.span,
ty::BoundConstness::NotConst,
ty::PredicatePolarity::Positive,
dummy_self,
&mut bounds,
// True so we don't populate `bounds` with associated type bounds, even
// though they're disallowed from object types.
OnlySelfBounds(true),
) {
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::PredicatePolarity::Positive);
trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span));
}
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(_) => {
span_bug!(span, "did not expect {pred} clause in object bounds");
}
}
}
// 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.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
if regular_traits.len() > 1 {
let _ = self.report_trait_object_addition_traits_error(&regular_traits);
} else if regular_traits.is_empty() && auto_traits.is_empty() {
let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
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 =
hir_ty_lowering_object_safety_violations(tcx, item.trait_ref().def_id());
if !object_safety_violations.is_empty() {
let reported = report_object_safety_error(
tcx,
span,
Some(hir_id),
item.trait_ref().def_id(),
&object_safety_violations,
)
.emit();
return Ty::new_error(tcx, reported);
}
}
let mut associated_types: FxIndexMap<Span, FxIndexSet<DefId>> = FxIndexMap::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) in regular_traits_refs_spans {
let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx);
for pred in traits::elaborate(tcx, [base_pred]).filter_only_self() {
debug!("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.is_impl_trait_in_trait())
.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 instantiated 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();
// FIXME(#120456) - is `swap_remove` correct?
def_ids.swap_remove(&def_id);
if tcx.generics_require_sized_self(def_id) {
tcx.emit_node_span_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_assoc_tys(
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);
debug!(?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 args: Vec<_> = trait_ref
.args
.iter()
.enumerate()
.skip(1) // Remove `Self` for `ExistentialPredicate`.
.map(|(index, arg)| {
if arg == dummy_self.into() {
let param = &generics.own_params[index];
missing_type_params.push(param.name);
Ty::new_misc_error(tcx).into()
} else if arg.walk().any(|arg| arg == dummy_self.into()) {
references_self = true;
let guar = tcx.dcx().span_delayed_bug(
span,
"trait object trait bounds reference `Self`",
);
replace_dummy_self_with_error(tcx, arg, guar)
} else {
arg
}
})
.collect();
let args = tcx.mk_args(&args);
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 reported = struct_span_code_err!(
tcx.dcx(),
i.bottom().1,
E0038,
"the {} `{}` cannot be made into an object",
tcx.def_descr(def_id),
tcx.item_name(def_id),
)
.with_note(
rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![])
.error_msg(),
)
.emit();
self.set_tainted_by_errors(reported);
}
ty::ExistentialTraitRef { def_id: trait_ref.def_id, args }
})
});
let existential_projections = projection_bounds.iter().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.args.iter().skip(1).any(|arg| {
if arg.walk().any(|arg| arg == dummy_self.into()) {
return true;
}
false
});
if references_self {
let guar = tcx
.dcx()
.span_delayed_bug(span, "trait object projection bounds reference `Self`");
b.projection_ty = replace_dummy_self_with_error(tcx, b.projection_ty, guar);
}
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.lower_lifetime(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.lower_lifetime(lifetime, None)
} else {
self.re_infer(None, span).unwrap_or_else(|| {
let err = struct_span_code_err!(
tcx.dcx(),
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()
};
self.set_tainted_by_errors(e);
ty::Region::new_error(tcx, e)
})
}
})
};
debug!(?region_bound);
Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
}
}
fn replace_dummy_self_with_error<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
tcx: TyCtxt<'tcx>,
t: T,
guar: ErrorGuaranteed,
) -> T {
t.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| {
if ty == tcx.types.trait_object_dummy_self { Ty::new_error(tcx, guar) } else { ty }
},
lt_op: |lt| lt,
ct_op: |ct| ct,
})
}