• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use rustc_data_structures::fx::FxHashMap;
2 use rustc_errors::struct_span_err;
3 use rustc_hir as hir;
4 use rustc_hir::def::{DefKind, Res};
5 use rustc_hir::def_id::{DefId, LocalDefId};
6 use rustc_lint_defs::Applicability;
7 use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
8 use rustc_span::symbol::Ident;
9 use rustc_span::{ErrorGuaranteed, Span};
10 use rustc_trait_selection::traits;
11 
12 use crate::astconv::{
13     AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
14 };
15 use crate::bounds::Bounds;
16 use crate::errors::{MultipleRelaxedDefaultBounds, ValueOfAssociatedStructAlreadySpecified};
17 
18 impl<'tcx> dyn AstConv<'tcx> + '_ {
19     /// Sets `implicitly_sized` to true on `Bounds` if necessary
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, )20     pub(crate) fn add_implicitly_sized(
21         &self,
22         bounds: &mut Bounds<'tcx>,
23         self_ty: Ty<'tcx>,
24         ast_bounds: &'tcx [hir::GenericBound<'tcx>],
25         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
26         span: Span,
27     ) {
28         let tcx = self.tcx();
29 
30         // Try to find an unbound in bounds.
31         let mut unbound = None;
32         let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
33             for ab in ast_bounds {
34                 if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
35                     if unbound.is_none() {
36                         unbound = Some(&ptr.trait_ref);
37                     } else {
38                         tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span });
39                     }
40                 }
41             }
42         };
43         search_bounds(ast_bounds);
44         if let Some((self_ty, where_clause)) = self_ty_where_predicates {
45             for clause in where_clause {
46                 if let hir::WherePredicate::BoundPredicate(pred) = clause {
47                     if pred.is_param_bound(self_ty.to_def_id()) {
48                         search_bounds(pred.bounds);
49                     }
50                 }
51             }
52         }
53 
54         let sized_def_id = tcx.lang_items().sized_trait();
55         match (&sized_def_id, unbound) {
56             (Some(sized_def_id), Some(tpb))
57                 if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) =>
58             {
59                 // There was in fact a `?Sized` bound, return without doing anything
60                 return;
61             }
62             (_, Some(_)) => {
63                 // There was a `?Trait` bound, but it was not `?Sized`; warn.
64                 tcx.sess.span_warn(
65                     span,
66                     "default bound relaxed for a type parameter, but \
67                         this does nothing because the given bound is not \
68                         a default; only `?Sized` is supported",
69                 );
70                 // Otherwise, add implicitly sized if `Sized` is available.
71             }
72             _ => {
73                 // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
74             }
75         }
76         if sized_def_id.is_none() {
77             // No lang item for `Sized`, so we can't add it as a bound.
78             return;
79         }
80         bounds.push_sized(tcx, self_ty, span);
81     }
82 
83     /// This helper takes a *converted* parameter type (`param_ty`)
84     /// and an *unconverted* list of bounds:
85     ///
86     /// ```text
87     /// fn foo<T: Debug>
88     ///        ^  ^^^^^ `ast_bounds` parameter, in HIR form
89     ///        |
90     ///        `param_ty`, in ty form
91     /// ```
92     ///
93     /// It adds these `ast_bounds` into the `bounds` structure.
94     ///
95     /// **A note on binders:** there is an implied binder around
96     /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
97     /// for more details.
98     #[instrument(level = "debug", skip(self, ast_bounds, bounds))]
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, )99     pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>>(
100         &self,
101         param_ty: Ty<'tcx>,
102         ast_bounds: I,
103         bounds: &mut Bounds<'tcx>,
104         bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
105         only_self_bounds: OnlySelfBounds,
106     ) {
107         for ast_bound in ast_bounds {
108             match ast_bound {
109                 hir::GenericBound::Trait(poly_trait_ref, modifier) => {
110                     let (constness, polarity) = match modifier {
111                         hir::TraitBoundModifier::MaybeConst => {
112                             (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
113                         }
114                         hir::TraitBoundModifier::None => {
115                             (ty::BoundConstness::NotConst, ty::ImplPolarity::Positive)
116                         }
117                         hir::TraitBoundModifier::Negative => {
118                             (ty::BoundConstness::NotConst, ty::ImplPolarity::Negative)
119                         }
120                         hir::TraitBoundModifier::Maybe => continue,
121                     };
122                     let _ = self.instantiate_poly_trait_ref(
123                         &poly_trait_ref.trait_ref,
124                         poly_trait_ref.span,
125                         constness,
126                         polarity,
127                         param_ty,
128                         bounds,
129                         false,
130                         only_self_bounds,
131                     );
132                 }
133                 &hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
134                     self.instantiate_lang_item_trait_ref(
135                         lang_item,
136                         span,
137                         hir_id,
138                         args,
139                         param_ty,
140                         bounds,
141                         only_self_bounds,
142                     );
143                 }
144                 hir::GenericBound::Outlives(lifetime) => {
145                     let region = self.ast_region_to_region(lifetime, None);
146                     bounds.push_region_bound(
147                         self.tcx(),
148                         ty::Binder::bind_with_vars(
149                             ty::OutlivesPredicate(param_ty, region),
150                             bound_vars,
151                         ),
152                         lifetime.ident.span,
153                     );
154                 }
155             }
156         }
157     }
158 
159     /// Translates a list of bounds from the HIR into the `Bounds` data structure.
160     /// The self-type for the bounds is given by `param_ty`.
161     ///
162     /// Example:
163     ///
164     /// ```ignore (illustrative)
165     /// fn foo<T: Bar + Baz>() { }
166     /// //     ^  ^^^^^^^^^ ast_bounds
167     /// //     param_ty
168     /// ```
169     ///
170     /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
171     /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
172     /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
173     ///
174     /// `span` should be the declaration size of the parameter.
compute_bounds( &self, param_ty: Ty<'tcx>, ast_bounds: &[hir::GenericBound<'_>], filter: PredicateFilter, ) -> Bounds<'tcx>175     pub(crate) fn compute_bounds(
176         &self,
177         param_ty: Ty<'tcx>,
178         ast_bounds: &[hir::GenericBound<'_>],
179         filter: PredicateFilter,
180     ) -> Bounds<'tcx> {
181         let mut bounds = Bounds::default();
182 
183         let only_self_bounds = match filter {
184             PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {
185                 OnlySelfBounds(false)
186             }
187             PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => OnlySelfBounds(true),
188         };
189 
190         self.add_bounds(
191             param_ty,
192             ast_bounds.iter().filter(|bound| {
193                 match filter {
194                 PredicateFilter::All
195                 | PredicateFilter::SelfOnly
196                 | PredicateFilter::SelfAndAssociatedTypeBounds => true,
197                 PredicateFilter::SelfThatDefines(assoc_name) => {
198                     if let Some(trait_ref) = bound.trait_ref()
199                         && let Some(trait_did) = trait_ref.trait_def_id()
200                         && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
201                     {
202                         true
203                     } else {
204                         false
205                     }
206                 }
207             }
208             }),
209             &mut bounds,
210             ty::List::empty(),
211             only_self_bounds,
212         );
213         debug!(?bounds);
214 
215         bounds
216     }
217 
218     /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates
219     /// onto `bounds`.
220     ///
221     /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
222     /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
223     /// the binder (e.g., `&'a u32`) and hence may reference bound regions.
224     #[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))]
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>225     pub(super) fn add_predicates_for_ast_type_binding(
226         &self,
227         hir_ref_id: hir::HirId,
228         trait_ref: ty::PolyTraitRef<'tcx>,
229         binding: &ConvertedBinding<'_, 'tcx>,
230         bounds: &mut Bounds<'tcx>,
231         speculative: bool,
232         dup_bindings: &mut FxHashMap<DefId, Span>,
233         path_span: Span,
234         constness: ty::BoundConstness,
235         only_self_bounds: OnlySelfBounds,
236         polarity: ty::ImplPolarity,
237     ) -> Result<(), ErrorGuaranteed> {
238         // Given something like `U: SomeTrait<T = X>`, we want to produce a
239         // predicate like `<U as SomeTrait>::T = X`. This is somewhat
240         // subtle in the event that `T` is defined in a supertrait of
241         // `SomeTrait`, because in that case we need to upcast.
242         //
243         // That is, consider this case:
244         //
245         // ```
246         // trait SubTrait: SuperTrait<i32> { }
247         // trait SuperTrait<A> { type T; }
248         //
249         // ... B: SubTrait<T = foo> ...
250         // ```
251         //
252         // We want to produce `<B as SuperTrait<i32>>::T == foo`.
253 
254         let tcx = self.tcx();
255 
256         let return_type_notation =
257             binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation;
258 
259         let candidate = if return_type_notation {
260             if self.trait_defines_associated_item_named(
261                 trait_ref.def_id(),
262                 ty::AssocKind::Fn,
263                 binding.item_name,
264             ) {
265                 trait_ref
266             } else {
267                 self.one_bound_for_assoc_method(
268                     traits::supertraits(tcx, trait_ref),
269                     trait_ref.print_only_trait_path(),
270                     binding.item_name,
271                     path_span,
272                 )?
273             }
274         } else if self.trait_defines_associated_item_named(
275             trait_ref.def_id(),
276             ty::AssocKind::Type,
277             binding.item_name,
278         ) {
279             // Simple case: X is defined in the current trait.
280             trait_ref
281         } else {
282             // Otherwise, we have to walk through the supertraits to find
283             // those that do.
284             self.one_bound_for_assoc_type(
285                 || traits::supertraits(tcx, trait_ref),
286                 trait_ref.skip_binder().print_only_trait_name(),
287                 binding.item_name,
288                 path_span,
289                 match binding.kind {
290                     ConvertedBindingKind::Equality(term) => Some(term),
291                     _ => None,
292                 },
293             )?
294         };
295 
296         let (assoc_ident, def_scope) =
297             tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
298 
299         // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
300         // of calling `filter_by_name_and_kind`.
301         let find_item_of_kind = |kind| {
302             tcx.associated_items(candidate.def_id())
303                 .filter_by_name_unhygienic(assoc_ident.name)
304                 .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
305         };
306         let assoc_item = if return_type_notation {
307             find_item_of_kind(ty::AssocKind::Fn)
308         } else {
309             find_item_of_kind(ty::AssocKind::Type)
310                 .or_else(|| find_item_of_kind(ty::AssocKind::Const))
311         }
312         .expect("missing associated type");
313 
314         if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
315             tcx.sess
316                 .struct_span_err(
317                     binding.span,
318                     format!("{} `{}` is private", assoc_item.kind, binding.item_name),
319                 )
320                 .span_label(binding.span, format!("private {}", assoc_item.kind))
321                 .emit();
322         }
323         tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
324 
325         if !speculative {
326             dup_bindings
327                 .entry(assoc_item.def_id)
328                 .and_modify(|prev_span| {
329                     tcx.sess.emit_err(ValueOfAssociatedStructAlreadySpecified {
330                         span: binding.span,
331                         prev_span: *prev_span,
332                         item_name: binding.item_name,
333                         def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
334                     });
335                 })
336                 .or_insert(binding.span);
337         }
338 
339         let projection_ty = if return_type_notation {
340             let mut emitted_bad_param_err = false;
341             // If we have an method return type bound, then we need to substitute
342             // the method's early bound params with suitable late-bound params.
343             let mut num_bound_vars = candidate.bound_vars().len();
344             let substs =
345                 candidate.skip_binder().substs.extend_to(tcx, assoc_item.def_id, |param, _| {
346                     let subst = match param.kind {
347                         ty::GenericParamDefKind::Lifetime => ty::Region::new_late_bound(
348                             tcx,
349                             ty::INNERMOST,
350                             ty::BoundRegion {
351                                 var: ty::BoundVar::from_usize(num_bound_vars),
352                                 kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name),
353                             },
354                         )
355                         .into(),
356                         ty::GenericParamDefKind::Type { .. } => {
357                             if !emitted_bad_param_err {
358                                 tcx.sess.emit_err(
359                                     crate::errors::ReturnTypeNotationIllegalParam::Type {
360                                         span: path_span,
361                                         param_span: tcx.def_span(param.def_id),
362                                     },
363                                 );
364                                 emitted_bad_param_err = true;
365                             }
366                             Ty::new_bound(
367                                 tcx,
368                                 ty::INNERMOST,
369                                 ty::BoundTy {
370                                     var: ty::BoundVar::from_usize(num_bound_vars),
371                                     kind: ty::BoundTyKind::Param(param.def_id, param.name),
372                                 },
373                             )
374                             .into()
375                         }
376                         ty::GenericParamDefKind::Const { .. } => {
377                             if !emitted_bad_param_err {
378                                 tcx.sess.emit_err(
379                                     crate::errors::ReturnTypeNotationIllegalParam::Const {
380                                         span: path_span,
381                                         param_span: tcx.def_span(param.def_id),
382                                     },
383                                 );
384                                 emitted_bad_param_err = true;
385                             }
386                             let ty = tcx
387                                 .type_of(param.def_id)
388                                 .no_bound_vars()
389                                 .expect("ct params cannot have early bound vars");
390                             ty::Const::new_bound(
391                                 tcx,
392                                 ty::INNERMOST,
393                                 ty::BoundVar::from_usize(num_bound_vars),
394                                 ty,
395                             )
396                             .into()
397                         }
398                     };
399                     num_bound_vars += 1;
400                     subst
401                 });
402 
403             // Next, we need to check that the return-type notation is being used on
404             // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait).
405             let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output();
406             let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
407                 && tcx.is_impl_trait_in_trait(alias_ty.def_id)
408             {
409                 alias_ty
410             } else {
411                 return Err(self.tcx().sess.emit_err(
412                     crate::errors::ReturnTypeNotationOnNonRpitit {
413                         span: binding.span,
414                         ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
415                         fn_span: tcx.hir().span_if_local(assoc_item.def_id),
416                         note: (),
417                     },
418                 ));
419             };
420 
421             // Finally, move the fn return type's bound vars over to account for the early bound
422             // params (and trait ref's late bound params). This logic is very similar to
423             // `Predicate::subst_supertrait`, and it's no coincidence why.
424             let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
425             let subst_output = ty::EarlyBinder::bind(shifted_output).subst(tcx, substs);
426 
427             let bound_vars = tcx.late_bound_vars(binding.hir_id);
428             ty::Binder::bind_with_vars(subst_output, bound_vars)
429         } else {
430             // Include substitutions for generic parameters of associated types
431             candidate.map_bound(|trait_ref| {
432                 let ident = Ident::new(assoc_item.name, binding.item_name.span);
433                 let item_segment = hir::PathSegment {
434                     ident,
435                     hir_id: binding.hir_id,
436                     res: Res::Err,
437                     args: Some(binding.gen_args),
438                     infer_args: false,
439                 };
440 
441                 let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
442                     path_span,
443                     assoc_item.def_id,
444                     &item_segment,
445                     trait_ref.substs,
446                 );
447 
448                 debug!(?substs_trait_ref_and_assoc_item);
449 
450                 tcx.mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
451             })
452         };
453 
454         if !speculative {
455             // Find any late-bound regions declared in `ty` that are not
456             // declared in the trait-ref or assoc_item. These are not well-formed.
457             //
458             // Example:
459             //
460             //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
461             //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
462             if let ConvertedBindingKind::Equality(ty) = binding.kind {
463                 let late_bound_in_trait_ref =
464                     tcx.collect_constrained_late_bound_regions(&projection_ty);
465                 let late_bound_in_ty =
466                     tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
467                 debug!(?late_bound_in_trait_ref);
468                 debug!(?late_bound_in_ty);
469 
470                 // FIXME: point at the type params that don't have appropriate lifetimes:
471                 // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
472                 //                         ----  ----     ^^^^^^^
473                 self.validate_late_bound_regions(
474                     late_bound_in_trait_ref,
475                     late_bound_in_ty,
476                     |br_name| {
477                         struct_span_err!(
478                             tcx.sess,
479                             binding.span,
480                             E0582,
481                             "binding for associated type `{}` references {}, \
482                              which does not appear in the trait input types",
483                             binding.item_name,
484                             br_name
485                         )
486                     },
487                 );
488             }
489         }
490 
491         match binding.kind {
492             ConvertedBindingKind::Equality(..) if return_type_notation => {
493                 return Err(self.tcx().sess.emit_err(
494                     crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
495                 ));
496             }
497             ConvertedBindingKind::Equality(mut term) => {
498                 // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
499                 // the "projection predicate" for:
500                 //
501                 // `<T as Iterator>::Item = u32`
502                 let assoc_item_def_id = projection_ty.skip_binder().def_id;
503                 let def_kind = tcx.def_kind(assoc_item_def_id);
504                 match (def_kind, term.unpack()) {
505                     (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_))
506                     | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (),
507                     (_, _) => {
508                         let got = if let Some(_) = term.ty() { "type" } else { "constant" };
509                         let expected = tcx.def_descr(assoc_item_def_id);
510                         let mut err = tcx.sess.struct_span_err(
511                             binding.span,
512                             format!("expected {expected} bound, found {got}"),
513                         );
514                         err.span_note(
515                             tcx.def_span(assoc_item_def_id),
516                             format!("{expected} defined here"),
517                         );
518 
519                         if let hir::def::DefKind::AssocConst = def_kind
520                           && let Some(t) = term.ty() && (t.is_enum() || t.references_error())
521                           && tcx.features().associated_const_equality {
522                             err.span_suggestion(
523                                 binding.span,
524                                 "if equating a const, try wrapping with braces",
525                                 format!("{} = {{ const }}", binding.item_name),
526                                 Applicability::HasPlaceholders,
527                             );
528                         }
529                         let reported = err.emit();
530                         term = match def_kind {
531                             hir::def::DefKind::AssocTy => Ty::new_error(tcx, reported).into(),
532                             hir::def::DefKind::AssocConst => ty::Const::new_error(
533                                 tcx,
534                                 reported,
535                                 tcx.type_of(assoc_item_def_id)
536                                     .subst(tcx, projection_ty.skip_binder().substs),
537                             )
538                             .into(),
539                             _ => unreachable!(),
540                         };
541                     }
542                 }
543                 bounds.push_projection_bound(
544                     tcx,
545                     projection_ty
546                         .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
547                     binding.span,
548                 );
549             }
550             ConvertedBindingKind::Constraint(ast_bounds) => {
551                 // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
552                 //
553                 // `<T as Iterator>::Item: Debug`
554                 //
555                 // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
556                 // parameter to have a skipped binder.
557                 //
558                 // NOTE: If `only_self_bounds` is true, do NOT expand this associated
559                 // type bound into a trait predicate, since we only want to add predicates
560                 // for the `Self` type.
561                 if !only_self_bounds.0 {
562                     let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
563                     self.add_bounds(
564                         param_ty,
565                         ast_bounds.iter(),
566                         bounds,
567                         projection_ty.bound_vars(),
568                         only_self_bounds,
569                     );
570                 }
571             }
572         }
573         Ok(())
574     }
575 }
576