fn default_constness_for_trait_bounds(&self) -> Constness;
- /// Returns predicates in scope of the form `X: Foo`, where `X` is
- /// a type parameter `X` with the given id `def_id`. This is a
- /// subset of the full set of predicates.
+ /// Returns predicates in scope of the form `X: Foo<T>`, where `X`
+ /// is a type parameter `X` with the given id `def_id` and T
+ /// matches `assoc_name`. This is a subset of the full set of
+ /// predicates.
///
/// This is used for one specific purpose: resolving "short-hand"
/// associated type references like `T::Item`. In principle, we
/// but this can lead to cycle errors. The problem is that we have
/// to do this resolution *in order to create the predicates in
/// the first place*. Hence, we have this "special pass".
- fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>;
+ fn get_type_parameter_bounds(
+ &self,
+ span: Span,
+ def_id: DefId,
+ assoc_name: Ident,
+ ) -> ty::GenericPredicates<'tcx>;
/// Returns the lifetime to use when a lifetime is omitted (and not elided).
fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span)
}
// Returns `true` if a bounds list includes `?Sized`.
- pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool {
+ pub fn is_unsized(&self, ast_bounds: &[&hir::GenericBound<'_>], span: Span) -> bool {
let tcx = self.tcx();
// Try to find an unbound in bounds.
fn add_bounds(
&self,
param_ty: Ty<'tcx>,
- ast_bounds: &[hir::GenericBound<'_>],
+ ast_bounds: &[&hir::GenericBound<'_>],
bounds: &mut Bounds<'tcx>,
) {
let constness = self.default_constness_for_trait_bounds();
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self
.instantiate_lang_item_trait_ref(
- lang_item, span, hir_id, args, param_ty, bounds,
+ *lang_item, *span, *hir_id, args, param_ty, bounds,
),
hir::GenericBound::Outlives(ref l) => bounds
.region_bounds
ast_bounds: &[hir::GenericBound<'_>],
sized_by_default: SizedByDefault,
span: Span,
+ ) -> Bounds<'tcx> {
+ let ast_bounds: Vec<_> = ast_bounds.iter().collect();
+ self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span)
+ }
+
+ /// 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 fn compute_bounds_that_match_assoc_type(
+ &self,
+ param_ty: Ty<'tcx>,
+ ast_bounds: &[hir::GenericBound<'_>],
+ sized_by_default: SizedByDefault,
+ span: Span,
+ 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() {
+ if let Some(trait_did) = trait_ref.trait_def_id() {
+ if self.tcx().trait_may_define_assoc_type(trait_did, assoc_name) {
+ result.push(ast_bound);
+ }
+ }
+ }
+ }
+
+ self.compute_bounds_inner(param_ty, &result, sized_by_default, span)
+ }
+
+ fn compute_bounds_inner(
+ &self,
+ param_ty: Ty<'tcx>,
+ ast_bounds: &[&hir::GenericBound<'_>],
+ sized_by_default: SizedByDefault,
+ span: Span,
) -> Bounds<'tcx> {
let mut bounds = Bounds::default();
self.add_bounds(param_ty, ast_bounds, &mut bounds);
- bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id());
bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
if !self.is_unsized(ast_bounds, span) { Some(span) } else { None }
//
// We want to produce `<B as SuperTrait<i32>>::T == foo`.
- debug!(
- "add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}",
- hir_ref_id, trait_ref, binding, bounds
- );
+ debug!(?hir_ref_id, ?trait_ref, ?binding, ?bounds, "add_predicates_for_ast_type_binding",);
let tcx = self.tcx();
let candidate =
// parameter to have a skipped binder.
let param_ty =
tcx.mk_projection(assoc_ty.def_id, projection_ty.skip_binder().substs);
- self.add_bounds(param_ty, ast_bounds, bounds);
+ let ast_bounds: Vec<_> = ast_bounds.iter().collect();
+ self.add_bounds(param_ty, &ast_bounds, bounds);
}
}
Ok(())
// De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
// `dyn Trait + Send`.
- auto_traits.sort_by_key(|i| i.trait_ref().def_id());
- auto_traits.dedup_by_key(|i| i.trait_ref().def_id());
+ // 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);
- // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
- // removing the dummy `Self` type (`trait_object_dummy_self`).
- let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| {
- if trait_ref.self_ty() != dummy_self {
- // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
- // which picks up non-supertraits where clauses - but also, the object safety
- // completely ignores trait aliases, which could be object safety hazards. We
- // `delay_span_bug` here to avoid an ICE in stable even when the feature is
- // disabled. (#66420)
- tcx.sess.delay_span_bug(
- DUMMY_SP,
- &format!(
- "trait_ref_to_existential called on {:?} with non-dummy Self",
- trait_ref,
- ),
- );
- }
- ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
- };
-
// 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_to_existential));
+ let existential_trait_refs = regular_traits.iter().map(|i| {
+ i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
+ if trait_ref.self_ty() != dummy_self {
+ // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
+ // which picks up non-supertraits where clauses - but also, the object safety
+ // completely ignores trait aliases, which could be object safety hazards. We
+ // `delay_span_bug` here to avoid an ICE in stable even when the feature is
+ // disabled. (#66420)
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ &format!(
+ "trait_ref_to_existential called on {:?} with non-dummy Self",
+ trait_ref,
+ ),
+ );
+ }
+ ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+ })
+ });
let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
bound.map_bound(|b| {
- let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
- ty::ExistentialProjection {
- ty: b.ty,
- item_def_id: b.projection_ty.item_def_id,
- substs: trait_ref.substs,
+ if b.projection_ty.self_ty() != dummy_self {
+ tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ &format!("trait_ref_to_existential called on {:?} with non-dummy Self", b),
+ );
}
+ ty::ExistentialProjection::erase_self_ty(tcx, b)
})
});
name: Symbol,
) {
let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
- if let (Some(_), Ok(snippet)) = (
- self.tcx().sess.confused_type_with_std_module.borrow().get(&span),
+ if let (true, Ok(snippet)) = (
+ self.tcx()
+ .sess
+ .confused_type_with_std_module
+ .borrow()
+ .keys()
+ .any(|full_span| full_span.contains(span)),
self.tcx().sess.source_map().span_to_snippet(span),
) {
err.span_suggestion(
ty_param_def_id, assoc_name, span,
);
- let predicates =
- &self.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates;
+ let predicates = &self
+ .get_type_parameter_bounds(span, ty_param_def_id.to_def_id(), assoc_name)
+ .predicates;
debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
let param_name = tcx.hir().ty_param_name(param_hir_id);
self.one_bound_for_assoc_type(
|| {
- traits::transitive_bounds(
+ traits::transitive_bounds_that_define_assoc_type(
tcx,
predicates.iter().filter_map(|(p, _)| {
p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value)
}),
+ assoc_name,
)
},
|| param_name.to_string(),
// the whole path.
// Will fail except for `T::A` and `Self::A`; i.e., if `qself_ty`/`qself_def` are not a type
// parameter or `Self`.
+ // NOTE: When this function starts resolving `Trait::AssocTy` successfully
+ // it should also start reportint the `BARE_TRAIT_OBJECTS` lint.
pub fn associated_path_to_ty(
&self,
hir_ref_id: hir::HirId,
}
hir::TyKind::BareFn(ref bf) => {
require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
+
tcx.mk_fn_ptr(self.ty_of_fn(
bf.unsafety,
bf.abi,
&bf.decl,
&hir::Generics::empty(),
None,
+ Some(ast_ty),
))
}
- hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
+ hir::TyKind::TraitObject(ref bounds, ref lifetime, _) => {
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed)
}
hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
self.res_to_ty(opt_self_ty, path, false)
}
hir::TyKind::OpaqueDef(item_id, ref lifetimes) => {
- let opaque_ty = tcx.hir().expect_item(item_id.id);
- let def_id = tcx.hir().local_def_id(item_id.id).to_def_id();
+ let opaque_ty = tcx.hir().item(item_id);
+ let def_id = item_id.def_id.to_def_id();
match opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
decl: &hir::FnDecl<'_>,
generics: &hir::Generics<'_>,
ident_span: Option<Span>,
+ hir_ty: Option<&hir::Ty<'_>>,
) -> ty::PolyFnSig<'tcx> {
debug!("ty_of_fn");
// only want to emit an error complaining about them if infer types (`_`) are not
// allowed. `allow_ty_infer` gates this behavior. We check for the presence of
// `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
+
crate::collect::placeholder_type_error(
tcx,
ident_span.map(|sp| sp.shrink_to_hi()),
- &generics.params[..],
+ generics.params,
visitor.0,
true,
+ hir_ty,
);
}