]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
1 | /*! |
2 | ||
3 | # typeck: check phase | |
4 | ||
5 | Within the check phase of type check, we check each item one at a time | |
6 | (bodies of function expressions are checked as part of the containing | |
7 | function). Inference is used to supply types wherever they are unknown. | |
8 | ||
9 | By far the most complex case is checking the body of a function. This | |
10 | can be broken down into several distinct phases: | |
11 | ||
12 | - gather: creates type variables to represent the type of each local | |
13 | variable and pattern binding. | |
14 | ||
15 | - main: the main pass does the lion's share of the work: it | |
16 | determines the types of all expressions, resolves | |
17 | methods, checks for most invalid conditions, and so forth. In | |
18 | some cases, where a type is unknown, it may create a type or region | |
19 | variable and use that as the type of an expression. | |
20 | ||
21 | In the process of checking, various constraints will be placed on | |
22 | these type variables through the subtyping relationships requested | |
23 | through the `demand` module. The `infer` module is in charge | |
24 | of resolving those constraints. | |
25 | ||
26 | - regionck: after main is complete, the regionck pass goes over all | |
27 | types looking for regions and making sure that they did not escape | |
064997fb | 28 | into places where they are not in scope. This may also influence the |
1b1a35ee XL |
29 | final assignments of the various region variables if there is some |
30 | flexibility. | |
31 | ||
32 | - writeback: writes the final types within a function body, replacing | |
33 | type variables with their final inferred types. These final types | |
34 | are written into the `tcx.node_types` table, which should *never* contain | |
35 | any reference to a type variable. | |
36 | ||
37 | ## Intermediate types | |
38 | ||
39 | While type checking a function, the intermediate types for the | |
40 | expressions, blocks, and so forth contained within the function are | |
41 | stored in `fcx.node_types` and `fcx.node_substs`. These types | |
42 | may contain unresolved type variables. After type checking is | |
43 | complete, the functions in the writeback module are used to take the | |
44 | types from this table, resolve them, and then write them into their | |
45 | permanent home in the type context `tcx`. | |
46 | ||
47 | This means that during inferencing you should use `fcx.write_ty()` | |
48 | and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of | |
49 | nodes within the function. | |
50 | ||
51 | The types of top-level items, which never contain unbound type | |
52 | variables, are stored directly into the `tcx` typeck_results. | |
53 | ||
54 | N.B., a type variable is not the same thing as a type parameter. A | |
5869c6ff XL |
55 | type variable is an instance of a type parameter. That is, |
56 | given a generic function `fn foo<T>(t: T)`, while checking the | |
1b1a35ee | 57 | function `foo`, the type `ty_param(0)` refers to the type `T`, which |
5869c6ff | 58 | is treated in abstract. However, when `foo()` is called, `T` will be |
1b1a35ee XL |
59 | substituted for a fresh type variable `N`. This variable will |
60 | eventually be resolved to some concrete type (which might itself be | |
5869c6ff | 61 | a type parameter). |
1b1a35ee XL |
62 | |
63 | */ | |
64 | ||
65 | pub mod _match; | |
66 | mod autoderef; | |
67 | mod callee; | |
68 | pub mod cast; | |
69 | mod check; | |
70 | mod closure; | |
71 | pub mod coercion; | |
72 | mod compare_method; | |
73 | pub mod demand; | |
74 | mod diverges; | |
75 | pub mod dropck; | |
76 | mod expectation; | |
77 | mod expr; | |
94222f64 | 78 | mod fallback; |
1b1a35ee XL |
79 | mod fn_ctxt; |
80 | mod gather_locals; | |
81 | mod generator_interior; | |
82 | mod inherited; | |
83 | pub mod intrinsic; | |
923072b8 | 84 | mod intrinsicck; |
1b1a35ee XL |
85 | pub mod method; |
86 | mod op; | |
87 | mod pat; | |
88 | mod place_op; | |
923072b8 | 89 | mod region; |
923072b8 | 90 | pub mod rvalue_scopes; |
1b1a35ee | 91 | mod upvar; |
064997fb | 92 | pub mod wfcheck; |
1b1a35ee XL |
93 | pub mod writeback; |
94 | ||
064997fb | 95 | use check::{check_abi, check_fn, check_mod_item_types}; |
1b1a35ee XL |
96 | pub use diverges::Diverges; |
97 | pub use expectation::Expectation; | |
29967ef6 | 98 | pub use fn_ctxt::*; |
1b1a35ee XL |
99 | pub use inherited::{Inherited, InheritedBuilder}; |
100 | ||
101 | use crate::astconv::AstConv; | |
102 | use crate::check::gather_locals::GatherLocalsVisitor; | |
103 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; | |
04454e1e | 104 | use rustc_errors::{ |
f2b60f7d | 105 | pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, |
04454e1e | 106 | }; |
1b1a35ee XL |
107 | use rustc_hir as hir; |
108 | use rustc_hir::def::Res; | |
17df50a5 | 109 | use rustc_hir::def_id::{DefId, LocalDefId}; |
1b1a35ee | 110 | use rustc_hir::intravisit::Visitor; |
fc512014 | 111 | use rustc_hir::{HirIdMap, ImplicitSelfKind, Node}; |
1b1a35ee | 112 | use rustc_index::bit_set::BitSet; |
29967ef6 | 113 | use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; |
1b1a35ee | 114 | use rustc_middle::ty::query::Providers; |
1b1a35ee | 115 | use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; |
136023e0 | 116 | use rustc_middle::ty::{self, Ty, TyCtxt, UserType}; |
1b1a35ee XL |
117 | use rustc_session::config; |
118 | use rustc_session::parse::feature_err; | |
119 | use rustc_session::Session; | |
136023e0 | 120 | use rustc_span::source_map::DUMMY_SP; |
1b1a35ee | 121 | use rustc_span::symbol::{kw, Ident}; |
f2b60f7d | 122 | use rustc_span::{self, BytePos, Span, Symbol}; |
1b1a35ee XL |
123 | use rustc_target::abi::VariantIdx; |
124 | use rustc_target::spec::abi::Abi; | |
125 | use rustc_trait_selection::traits; | |
126 | use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; | |
127 | use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; | |
064997fb | 128 | use std::cell::RefCell; |
f2b60f7d | 129 | use std::num::NonZeroU32; |
1b1a35ee XL |
130 | |
131 | use crate::require_c_abi_if_c_variadic; | |
132 | use crate::util::common::indenter; | |
133 | ||
134 | use self::coercion::DynamicCoerceMany; | |
f2b60f7d | 135 | use self::compare_method::collect_trait_impl_trait_tys; |
923072b8 | 136 | use self::region::region_scope_tree; |
1b1a35ee XL |
137 | pub use self::Expectation::*; |
138 | ||
139 | #[macro_export] | |
140 | macro_rules! type_error_struct { | |
141 | ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ | |
5e7ed085 FG |
142 | let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*); |
143 | ||
1b1a35ee | 144 | if $typ.references_error() { |
5e7ed085 | 145 | err.downgrade_to_delayed_bug(); |
1b1a35ee | 146 | } |
5e7ed085 FG |
147 | |
148 | err | |
1b1a35ee XL |
149 | }) |
150 | } | |
151 | ||
152 | /// The type of a local binding, including the revealed type for anon types. | |
153 | #[derive(Copy, Clone, Debug)] | |
154 | pub struct LocalTy<'tcx> { | |
155 | decl_ty: Ty<'tcx>, | |
156 | revealed_ty: Ty<'tcx>, | |
157 | } | |
158 | ||
159 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | |
160 | pub enum Needs { | |
161 | MutPlace, | |
162 | None, | |
163 | } | |
164 | ||
165 | impl Needs { | |
166 | fn maybe_mut_place(m: hir::Mutability) -> Self { | |
167 | match m { | |
168 | hir::Mutability::Mut => Needs::MutPlace, | |
169 | hir::Mutability::Not => Needs::None, | |
170 | } | |
171 | } | |
172 | } | |
173 | ||
174 | #[derive(Copy, Clone)] | |
175 | pub struct UnsafetyState { | |
176 | pub def: hir::HirId, | |
177 | pub unsafety: hir::Unsafety, | |
1b1a35ee XL |
178 | from_fn: bool, |
179 | } | |
180 | ||
181 | impl UnsafetyState { | |
182 | pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState { | |
136023e0 | 183 | UnsafetyState { def, unsafety, from_fn: true } |
1b1a35ee XL |
184 | } |
185 | ||
5869c6ff | 186 | pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState { |
1b1a35ee XL |
187 | use hir::BlockCheckMode; |
188 | match self.unsafety { | |
189 | // If this unsafe, then if the outer function was already marked as | |
190 | // unsafe we shouldn't attribute the unsafe'ness to the block. This | |
191 | // way the block can be warned about instead of ignoring this | |
192 | // extraneous block (functions are never warned about). | |
5869c6ff | 193 | hir::Unsafety::Unsafe if self.from_fn => self, |
1b1a35ee XL |
194 | |
195 | unsafety => { | |
136023e0 XL |
196 | let (unsafety, def) = match blk.rules { |
197 | BlockCheckMode::UnsafeBlock(..) => (hir::Unsafety::Unsafe, blk.hir_id), | |
198 | BlockCheckMode::DefaultBlock => (unsafety, self.def), | |
1b1a35ee | 199 | }; |
136023e0 | 200 | UnsafetyState { def, unsafety, from_fn: false } |
1b1a35ee XL |
201 | } |
202 | } | |
203 | } | |
204 | } | |
205 | ||
206 | #[derive(Debug, Copy, Clone)] | |
207 | pub enum PlaceOp { | |
208 | Deref, | |
209 | Index, | |
210 | } | |
211 | ||
212 | pub struct BreakableCtxt<'tcx> { | |
213 | may_break: bool, | |
214 | ||
215 | // this is `null` for loops where break with a value is illegal, | |
216 | // such as `while`, `for`, and `while let` | |
217 | coerce: Option<DynamicCoerceMany<'tcx>>, | |
218 | } | |
219 | ||
220 | pub struct EnclosingBreakables<'tcx> { | |
221 | stack: Vec<BreakableCtxt<'tcx>>, | |
222 | by_id: HirIdMap<usize>, | |
223 | } | |
224 | ||
225 | impl<'tcx> EnclosingBreakables<'tcx> { | |
226 | fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> { | |
227 | self.opt_find_breakable(target_id).unwrap_or_else(|| { | |
228 | bug!("could not find enclosing breakable with id {}", target_id); | |
229 | }) | |
230 | } | |
231 | ||
232 | fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> { | |
233 | match self.by_id.get(&target_id) { | |
234 | Some(ix) => Some(&mut self.stack[*ix]), | |
235 | None => None, | |
236 | } | |
237 | } | |
238 | } | |
239 | ||
240 | pub fn provide(providers: &mut Providers) { | |
241 | method::provide(providers); | |
064997fb | 242 | wfcheck::provide(providers); |
1b1a35ee XL |
243 | *providers = Providers { |
244 | typeck_item_bodies, | |
245 | typeck_const_arg, | |
246 | typeck, | |
247 | diagnostic_only_typeck, | |
248 | has_typeck_results, | |
249 | adt_destructor, | |
250 | used_trait_imports, | |
1b1a35ee | 251 | check_mod_item_types, |
923072b8 | 252 | region_scope_tree, |
f2b60f7d | 253 | collect_trait_impl_trait_tys, |
1b1a35ee XL |
254 | ..*providers |
255 | }; | |
256 | } | |
257 | ||
258 | fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> { | |
29967ef6 | 259 | tcx.calculate_dtor(def_id, dropck::check_drop_impl) |
1b1a35ee XL |
260 | } |
261 | ||
262 | /// If this `DefId` is a "primary tables entry", returns | |
94222f64 | 263 | /// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`. |
1b1a35ee XL |
264 | /// |
265 | /// If this function returns `Some`, then `typeck_results(def_id)` will | |
266 | /// succeed; if it returns `None`, then `typeck_results(def_id)` may or | |
267 | /// may not succeed. In some cases where this function returns `None` | |
268 | /// (notably closures), `typeck_results(def_id)` would wind up | |
269 | /// redirecting to the owning function. | |
270 | fn primary_body_of( | |
271 | tcx: TyCtxt<'_>, | |
272 | id: hir::HirId, | |
94222f64 | 273 | ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> { |
1b1a35ee XL |
274 | match tcx.hir().get(id) { |
275 | Node::Item(item) => match item.kind { | |
c295e0f8 | 276 | hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => { |
94222f64 | 277 | Some((body, Some(ty), None)) |
1b1a35ee | 278 | } |
c295e0f8 | 279 | hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))), |
1b1a35ee XL |
280 | _ => None, |
281 | }, | |
282 | Node::TraitItem(item) => match item.kind { | |
c295e0f8 | 283 | hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)), |
1b1a35ee | 284 | hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { |
c295e0f8 | 285 | Some((body, None, Some(sig))) |
1b1a35ee XL |
286 | } |
287 | _ => None, | |
288 | }, | |
289 | Node::ImplItem(item) => match item.kind { | |
c295e0f8 XL |
290 | hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)), |
291 | hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))), | |
1b1a35ee XL |
292 | _ => None, |
293 | }, | |
94222f64 | 294 | Node::AnonConst(constant) => Some((constant.body, None, None)), |
1b1a35ee XL |
295 | _ => None, |
296 | } | |
297 | } | |
298 | ||
299 | fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | |
300 | // Closures' typeck results come from their outermost function, | |
301 | // as they are part of the same "inference environment". | |
3c0e092e XL |
302 | let typeck_root_def_id = tcx.typeck_root_def_id(def_id); |
303 | if typeck_root_def_id != def_id { | |
304 | return tcx.has_typeck_results(typeck_root_def_id); | |
1b1a35ee XL |
305 | } |
306 | ||
307 | if let Some(def_id) = def_id.as_local() { | |
308 | let id = tcx.hir().local_def_id_to_hir_id(def_id); | |
309 | primary_body_of(tcx, id).is_some() | |
310 | } else { | |
311 | false | |
312 | } | |
313 | } | |
314 | ||
315 | fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> { | |
316 | &*tcx.typeck(def_id).used_trait_imports | |
317 | } | |
318 | ||
1b1a35ee XL |
319 | fn typeck_const_arg<'tcx>( |
320 | tcx: TyCtxt<'tcx>, | |
321 | (did, param_did): (LocalDefId, DefId), | |
322 | ) -> &ty::TypeckResults<'tcx> { | |
323 | let fallback = move || tcx.type_of(param_did); | |
324 | typeck_with_fallback(tcx, did, fallback) | |
325 | } | |
326 | ||
327 | fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { | |
328 | if let Some(param_did) = tcx.opt_const_param_of(def_id) { | |
329 | tcx.typeck_const_arg((def_id, param_did)) | |
330 | } else { | |
331 | let fallback = move || tcx.type_of(def_id.to_def_id()); | |
332 | typeck_with_fallback(tcx, def_id, fallback) | |
333 | } | |
334 | } | |
335 | ||
336 | /// Used only to get `TypeckResults` for type inference during error recovery. | |
337 | /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors. | |
338 | fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { | |
339 | let fallback = move || { | |
340 | let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id)); | |
341 | tcx.ty_error_with_message(span, "diagnostic only typeck table used") | |
342 | }; | |
343 | typeck_with_fallback(tcx, def_id, fallback) | |
344 | } | |
345 | ||
346 | fn typeck_with_fallback<'tcx>( | |
347 | tcx: TyCtxt<'tcx>, | |
348 | def_id: LocalDefId, | |
349 | fallback: impl Fn() -> Ty<'tcx> + 'tcx, | |
350 | ) -> &'tcx ty::TypeckResults<'tcx> { | |
351 | // Closures' typeck results come from their outermost function, | |
352 | // as they are part of the same "inference environment". | |
3c0e092e XL |
353 | let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(); |
354 | if typeck_root_def_id != def_id { | |
355 | return tcx.typeck(typeck_root_def_id); | |
1b1a35ee XL |
356 | } |
357 | ||
358 | let id = tcx.hir().local_def_id_to_hir_id(def_id); | |
359 | let span = tcx.hir().span(id); | |
360 | ||
361 | // Figure out what primary body this item has. | |
94222f64 | 362 | let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| { |
1b1a35ee XL |
363 | span_bug!(span, "can't type-check body of {:?}", def_id); |
364 | }); | |
365 | let body = tcx.hir().body(body_id); | |
366 | ||
367 | let typeck_results = Inherited::build(tcx, def_id).enter(|inh| { | |
368 | let param_env = tcx.param_env(def_id); | |
064997fb | 369 | let fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig { |
1b1a35ee XL |
370 | let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() { |
371 | let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); | |
04454e1e | 372 | <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None) |
1b1a35ee XL |
373 | } else { |
374 | tcx.fn_sig(def_id) | |
375 | }; | |
376 | ||
136023e0 | 377 | check_abi(tcx, id, span, fn_sig.abi()); |
1b1a35ee | 378 | |
064997fb | 379 | // Compute the function signature from point of view of inside the fn. |
fc512014 | 380 | let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); |
1b1a35ee XL |
381 | let fn_sig = inh.normalize_associated_types_in( |
382 | body.value.span, | |
383 | body_id.hir_id, | |
384 | param_env, | |
fc512014 | 385 | fn_sig, |
1b1a35ee | 386 | ); |
064997fb | 387 | check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0 |
1b1a35ee XL |
388 | } else { |
389 | let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); | |
390 | let expected_type = body_ty | |
391 | .and_then(|ty| match ty.kind { | |
6a06907d | 392 | hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)), |
1b1a35ee XL |
393 | _ => None, |
394 | }) | |
29967ef6 XL |
395 | .unwrap_or_else(|| match tcx.hir().get(id) { |
396 | Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) { | |
397 | Node::Expr(&hir::Expr { | |
398 | kind: hir::ExprKind::ConstBlock(ref anon_const), | |
399 | .. | |
400 | }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin { | |
401 | kind: TypeVariableOriginKind::TypeInference, | |
402 | span, | |
403 | }), | |
cdc7bbd5 XL |
404 | Node::Ty(&hir::Ty { |
405 | kind: hir::TyKind::Typeof(ref anon_const), .. | |
406 | }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin { | |
407 | kind: TypeVariableOriginKind::TypeInference, | |
408 | span, | |
409 | }), | |
17df50a5 | 410 | Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. }) |
04454e1e FG |
411 | | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => { |
412 | let operand_ty = asm | |
413 | .operands | |
414 | .iter() | |
415 | .filter_map(|(op, _op_sp)| match op { | |
416 | hir::InlineAsmOperand::Const { anon_const } | |
417 | if anon_const.hir_id == id => | |
418 | { | |
419 | // Inline assembly constants must be integers. | |
420 | Some(fcx.next_int_var()) | |
421 | } | |
422 | hir::InlineAsmOperand::SymFn { anon_const } | |
423 | if anon_const.hir_id == id => | |
424 | { | |
425 | Some(fcx.next_ty_var(TypeVariableOrigin { | |
426 | kind: TypeVariableOriginKind::MiscVariable, | |
427 | span, | |
428 | })) | |
429 | } | |
430 | _ => None, | |
431 | }) | |
432 | .next(); | |
433 | operand_ty.unwrap_or_else(fallback) | |
cdc7bbd5 | 434 | } |
29967ef6 XL |
435 | _ => fallback(), |
436 | }, | |
437 | _ => fallback(), | |
438 | }); | |
439 | ||
fc512014 | 440 | let expected_type = fcx.normalize_associated_types_in(body.value.span, expected_type); |
1b1a35ee XL |
441 | fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); |
442 | ||
1b1a35ee | 443 | // Gather locals in statics (because of block expressions). |
136023e0 | 444 | GatherLocalsVisitor::new(&fcx).visit_body(body); |
1b1a35ee | 445 | |
136023e0 | 446 | fcx.check_expr_coercable_to_type(&body.value, expected_type, None); |
1b1a35ee | 447 | |
136023e0 | 448 | fcx.write_ty(id, expected_type); |
1b1a35ee | 449 | |
064997fb | 450 | fcx |
1b1a35ee XL |
451 | }; |
452 | ||
94222f64 | 453 | let fallback_has_occurred = fcx.type_inference_fallback(); |
1b1a35ee XL |
454 | |
455 | // Even though coercion casts provide type hints, we check casts after fallback for | |
456 | // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. | |
457 | fcx.check_casts(); | |
94222f64 | 458 | fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); |
1b1a35ee XL |
459 | |
460 | // Closure and generator analysis may run after fallback | |
461 | // because they don't constrain other type variables. | |
462 | fcx.closure_analyze(body); | |
463 | assert!(fcx.deferred_call_resolutions.borrow().is_empty()); | |
923072b8 FG |
464 | // Before the generator analysis, temporary scopes shall be marked to provide more |
465 | // precise information on types to be captured. | |
466 | fcx.resolve_rvalue_scopes(def_id.to_def_id()); | |
1b1a35ee XL |
467 | fcx.resolve_generator_interiors(def_id.to_def_id()); |
468 | ||
469 | for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { | |
470 | let ty = fcx.normalize_ty(span, ty); | |
471 | fcx.require_type_is_sized(ty, span, code); | |
472 | } | |
473 | ||
474 | fcx.select_all_obligations_or_error(); | |
475 | ||
923072b8 FG |
476 | if !fcx.infcx.is_tainted_by_errors() { |
477 | fcx.check_transmutes(); | |
478 | } | |
479 | ||
480 | fcx.check_asms(); | |
481 | ||
064997fb | 482 | fcx.infcx.skip_region_resolution(); |
1b1a35ee XL |
483 | |
484 | fcx.resolve_type_vars_in_body(body) | |
485 | }); | |
486 | ||
487 | // Consistency check our TypeckResults instance can hold all ItemLocalIds | |
488 | // it will need to hold. | |
489 | assert_eq!(typeck_results.hir_owner, id.owner); | |
490 | ||
491 | typeck_results | |
492 | } | |
493 | ||
494 | /// When `check_fn` is invoked on a generator (i.e., a body that | |
495 | /// includes yield), it returns back some information about the yield | |
496 | /// points. | |
497 | struct GeneratorTypes<'tcx> { | |
498 | /// Type of generator argument / values returned by `yield`. | |
499 | resume_ty: Ty<'tcx>, | |
500 | ||
501 | /// Type of value that is yielded. | |
502 | yield_ty: Ty<'tcx>, | |
503 | ||
504 | /// Types that are captured (see `GeneratorInterior` for more). | |
505 | interior: Ty<'tcx>, | |
506 | ||
507 | /// Indicates if the generator is movable or static (immovable). | |
508 | movability: hir::Movability, | |
509 | } | |
510 | ||
511 | /// Given a `DefId` for an opaque type in return position, find its parent item's return | |
512 | /// expressions. | |
a2a8927a | 513 | fn get_owner_return_paths<'tcx>( |
1b1a35ee XL |
514 | tcx: TyCtxt<'tcx>, |
515 | def_id: LocalDefId, | |
5099ac24 | 516 | ) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> { |
1b1a35ee | 517 | let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); |
5099ac24 FG |
518 | let parent_id = tcx.hir().get_parent_item(hir_id); |
519 | tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| { | |
520 | let body = tcx.hir().body(body_id); | |
521 | let mut visitor = ReturnsVisitor::default(); | |
522 | visitor.visit_body(body); | |
523 | (parent_id, visitor) | |
524 | }) | |
1b1a35ee XL |
525 | } |
526 | ||
1b1a35ee XL |
527 | // Forbid defining intrinsics in Rust code, |
528 | // as they must always be defined by the compiler. | |
529 | fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { | |
530 | if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi { | |
531 | tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block"); | |
532 | } | |
533 | } | |
534 | ||
064997fb | 535 | fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { |
3c0e092e XL |
536 | // Only restricted on wasm target for now |
537 | if !tcx.sess.target.is_like_wasm { | |
1b1a35ee XL |
538 | return; |
539 | } | |
540 | ||
541 | // If `#[link_section]` is missing, then nothing to verify | |
542 | let attrs = tcx.codegen_fn_attrs(id); | |
543 | if attrs.link_section.is_none() { | |
544 | return; | |
545 | } | |
546 | ||
547 | // For the wasm32 target statics with `#[link_section]` are placed into custom | |
548 | // sections of the final output file, but this isn't link custom sections of | |
549 | // other executable formats. Namely we can only embed a list of bytes, | |
f2b60f7d FG |
550 | // nothing with provenance (pointers to anything else). If any provenance |
551 | // show up, reject it here. | |
1b1a35ee XL |
552 | // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is |
553 | // the consumer's responsibility to ensure all bytes that have been read | |
554 | // have defined values. | |
04454e1e | 555 | if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) |
f2b60f7d | 556 | && alloc.inner().provenance().len() != 0 |
04454e1e FG |
557 | { |
558 | let msg = "statics with a custom `#[link_section]` must be a \ | |
559 | simple list of bytes on the wasm target with no \ | |
560 | extra levels of indirection such as references"; | |
064997fb | 561 | tcx.sess.span_err(tcx.def_span(id), msg); |
1b1a35ee XL |
562 | } |
563 | } | |
564 | ||
565 | fn report_forbidden_specialization( | |
566 | tcx: TyCtxt<'_>, | |
5099ac24 | 567 | impl_item: &hir::ImplItemRef, |
1b1a35ee XL |
568 | parent_impl: DefId, |
569 | ) { | |
570 | let mut err = struct_span_err!( | |
571 | tcx.sess, | |
572 | impl_item.span, | |
573 | E0520, | |
574 | "`{}` specializes an item from a parent `impl`, but \ | |
575 | that item is not marked `default`", | |
576 | impl_item.ident | |
577 | ); | |
578 | err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident)); | |
579 | ||
580 | match tcx.span_of_impl(parent_impl) { | |
581 | Ok(span) => { | |
582 | err.span_label(span, "parent `impl` is here"); | |
583 | err.note(&format!( | |
584 | "to specialize, `{}` in the parent `impl` must be marked `default`", | |
585 | impl_item.ident | |
586 | )); | |
587 | } | |
588 | Err(cname) => { | |
04454e1e | 589 | err.note(&format!("parent implementation is in crate `{cname}`")); |
1b1a35ee XL |
590 | } |
591 | } | |
592 | ||
593 | err.emit(); | |
594 | } | |
595 | ||
596 | fn missing_items_err( | |
597 | tcx: TyCtxt<'_>, | |
598 | impl_span: Span, | |
5099ac24 | 599 | missing_items: &[&ty::AssocItem], |
1b1a35ee XL |
600 | full_impl_span: Span, |
601 | ) { | |
602 | let missing_items_msg = missing_items | |
603 | .iter() | |
5099ac24 | 604 | .map(|trait_item| trait_item.name.to_string()) |
1b1a35ee XL |
605 | .collect::<Vec<_>>() |
606 | .join("`, `"); | |
607 | ||
608 | let mut err = struct_span_err!( | |
609 | tcx.sess, | |
610 | impl_span, | |
611 | E0046, | |
04454e1e | 612 | "not all trait items implemented, missing: `{missing_items_msg}`", |
1b1a35ee | 613 | ); |
04454e1e | 614 | err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation")); |
1b1a35ee XL |
615 | |
616 | // `Span` before impl block closing brace. | |
617 | let hi = full_impl_span.hi() - BytePos(1); | |
618 | // Point at the place right before the closing brace of the relevant `impl` to suggest | |
619 | // adding the associated item at the end of its body. | |
620 | let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi); | |
621 | // Obtain the level of indentation ending in `sugg_sp`. | |
064997fb FG |
622 | let padding = |
623 | tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); | |
1b1a35ee XL |
624 | |
625 | for trait_item in missing_items { | |
c295e0f8 | 626 | let snippet = suggestion_signature(trait_item, tcx); |
1b1a35ee | 627 | let code = format!("{}{}\n{}", padding, snippet, padding); |
04454e1e | 628 | let msg = format!("implement the missing item: `{snippet}`"); |
1b1a35ee XL |
629 | let appl = Applicability::HasPlaceholders; |
630 | if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) { | |
5099ac24 | 631 | err.span_label(span, format!("`{}` from trait", trait_item.name)); |
1b1a35ee XL |
632 | err.tool_only_span_suggestion(sugg_sp, &msg, code, appl); |
633 | } else { | |
634 | err.span_suggestion_hidden(sugg_sp, &msg, code, appl); | |
635 | } | |
636 | } | |
637 | err.emit(); | |
638 | } | |
639 | ||
5099ac24 FG |
640 | fn missing_items_must_implement_one_of_err( |
641 | tcx: TyCtxt<'_>, | |
642 | impl_span: Span, | |
643 | missing_items: &[Ident], | |
644 | annotation_span: Option<Span>, | |
645 | ) { | |
646 | let missing_items_msg = | |
647 | missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `"); | |
648 | ||
649 | let mut err = struct_span_err!( | |
650 | tcx.sess, | |
651 | impl_span, | |
652 | E0046, | |
04454e1e | 653 | "not all trait items implemented, missing one of: `{missing_items_msg}`", |
5099ac24 | 654 | ); |
04454e1e | 655 | err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation")); |
5099ac24 FG |
656 | |
657 | if let Some(annotation_span) = annotation_span { | |
658 | err.span_note(annotation_span, "required because of this annotation"); | |
659 | } | |
660 | ||
661 | err.emit(); | |
662 | } | |
663 | ||
f2b60f7d FG |
664 | fn default_body_is_unstable( |
665 | tcx: TyCtxt<'_>, | |
666 | impl_span: Span, | |
667 | item_did: DefId, | |
668 | feature: Symbol, | |
669 | reason: Option<Symbol>, | |
670 | issue: Option<NonZeroU32>, | |
671 | ) { | |
672 | let missing_item_name = &tcx.associated_item(item_did).name; | |
673 | let use_of_unstable_library_feature_note = match reason { | |
674 | Some(r) => format!("use of unstable library feature '{feature}': {r}"), | |
675 | None => format!("use of unstable library feature '{feature}'"), | |
676 | }; | |
677 | ||
678 | let mut err = struct_span_err!( | |
679 | tcx.sess, | |
680 | impl_span, | |
681 | E0046, | |
682 | "not all trait items implemented, missing: `{missing_item_name}`", | |
683 | ); | |
684 | err.note(format!("default implementation of `{missing_item_name}` is unstable")); | |
685 | err.note(use_of_unstable_library_feature_note); | |
686 | rustc_session::parse::add_feature_diagnostics_for_issue( | |
687 | &mut err, | |
688 | &tcx.sess.parse_sess, | |
689 | feature, | |
690 | rustc_feature::GateIssue::Library(issue), | |
691 | ); | |
692 | err.emit(); | |
693 | } | |
694 | ||
5e7ed085 | 695 | /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. |
1b1a35ee XL |
696 | fn bounds_from_generic_predicates<'tcx>( |
697 | tcx: TyCtxt<'tcx>, | |
698 | predicates: ty::GenericPredicates<'tcx>, | |
699 | ) -> (String, String) { | |
700 | let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default(); | |
701 | let mut projections = vec![]; | |
702 | for (predicate, _) in predicates.predicates { | |
703 | debug!("predicate {:?}", predicate); | |
5869c6ff | 704 | let bound_predicate = predicate.kind(); |
29967ef6 | 705 | match bound_predicate.skip_binder() { |
94222f64 | 706 | ty::PredicateKind::Trait(trait_predicate) => { |
1b1a35ee XL |
707 | let entry = types.entry(trait_predicate.self_ty()).or_default(); |
708 | let def_id = trait_predicate.def_id(); | |
709 | if Some(def_id) != tcx.lang_items().sized_trait() { | |
710 | // Type params are `Sized` by default, do not add that restriction to the list | |
711 | // if it is a positive requirement. | |
712 | entry.push(trait_predicate.def_id()); | |
713 | } | |
714 | } | |
5869c6ff | 715 | ty::PredicateKind::Projection(projection_pred) => { |
29967ef6 | 716 | projections.push(bound_predicate.rebind(projection_pred)); |
1b1a35ee XL |
717 | } |
718 | _ => {} | |
719 | } | |
720 | } | |
721 | let generics = if types.is_empty() { | |
722 | "".to_string() | |
723 | } else { | |
724 | format!( | |
725 | "<{}>", | |
726 | types | |
727 | .keys() | |
728 | .filter_map(|t| match t.kind() { | |
729 | ty::Param(_) => Some(t.to_string()), | |
730 | // Avoid suggesting the following: | |
731 | // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {} | |
732 | _ => None, | |
733 | }) | |
734 | .collect::<Vec<_>>() | |
735 | .join(", ") | |
736 | ) | |
737 | }; | |
738 | let mut where_clauses = vec![]; | |
739 | for (ty, bounds) in types { | |
a2a8927a XL |
740 | where_clauses |
741 | .extend(bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound)))); | |
1b1a35ee XL |
742 | } |
743 | for projection in &projections { | |
744 | let p = projection.skip_binder(); | |
745 | // FIXME: this is not currently supported syntax, we should be looking at the `types` and | |
746 | // insert the associated types where they correspond, but for now let's be "lazy" and | |
747 | // propose this instead of the following valid resugaring: | |
748 | // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>` | |
5099ac24 FG |
749 | where_clauses.push(format!( |
750 | "{} = {}", | |
751 | tcx.def_path_str(p.projection_ty.item_def_id), | |
752 | p.term, | |
753 | )); | |
1b1a35ee XL |
754 | } |
755 | let where_clauses = if where_clauses.is_empty() { | |
756 | String::new() | |
757 | } else { | |
758 | format!(" where {}", where_clauses.join(", ")) | |
759 | }; | |
760 | (generics, where_clauses) | |
761 | } | |
762 | ||
763 | /// Return placeholder code for the given function. | |
764 | fn fn_sig_suggestion<'tcx>( | |
765 | tcx: TyCtxt<'tcx>, | |
766 | sig: ty::FnSig<'tcx>, | |
767 | ident: Ident, | |
768 | predicates: ty::GenericPredicates<'tcx>, | |
769 | assoc: &ty::AssocItem, | |
770 | ) -> String { | |
771 | let args = sig | |
772 | .inputs() | |
773 | .iter() | |
774 | .enumerate() | |
775 | .map(|(i, ty)| { | |
776 | Some(match ty.kind() { | |
777 | ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(), | |
778 | ty::Ref(reg, ref_ty, mutability) if i == 0 => { | |
04454e1e FG |
779 | let reg = format!("{reg} "); |
780 | let reg = match ®[..] { | |
781 | "'_ " | " " => "", | |
782 | reg => reg, | |
1b1a35ee XL |
783 | }; |
784 | if assoc.fn_has_self_parameter { | |
785 | match ref_ty.kind() { | |
786 | ty::Param(param) if param.name == kw::SelfUpper => { | |
787 | format!("&{}{}self", reg, mutability.prefix_str()) | |
788 | } | |
789 | ||
04454e1e | 790 | _ => format!("self: {ty}"), |
1b1a35ee XL |
791 | } |
792 | } else { | |
04454e1e | 793 | format!("_: {ty}") |
1b1a35ee XL |
794 | } |
795 | } | |
796 | _ => { | |
797 | if assoc.fn_has_self_parameter && i == 0 { | |
04454e1e | 798 | format!("self: {ty}") |
1b1a35ee | 799 | } else { |
04454e1e | 800 | format!("_: {ty}") |
1b1a35ee XL |
801 | } |
802 | } | |
803 | }) | |
804 | }) | |
805 | .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None })) | |
94222f64 | 806 | .flatten() |
1b1a35ee XL |
807 | .collect::<Vec<String>>() |
808 | .join(", "); | |
809 | let output = sig.output(); | |
04454e1e | 810 | let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() }; |
1b1a35ee XL |
811 | |
812 | let unsafety = sig.unsafety.prefix_str(); | |
813 | let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates); | |
814 | ||
815 | // FIXME: this is not entirely correct, as the lifetimes from borrowed params will | |
816 | // not be present in the `fn` definition, not will we account for renamed | |
817 | // lifetimes between the `impl` and the `trait`, but this should be good enough to | |
818 | // fill in a significant portion of the missing code, and other subsequent | |
819 | // suggestions can help the user fix the code. | |
04454e1e | 820 | format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}") |
1b1a35ee XL |
821 | } |
822 | ||
823 | /// Return placeholder code for the given associated item. | |
824 | /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a | |
825 | /// structured suggestion. | |
826 | fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { | |
827 | match assoc.kind { | |
828 | ty::AssocKind::Fn => { | |
829 | // We skip the binder here because the binder would deanonymize all | |
830 | // late-bound regions, and we don't want method signatures to show up | |
831 | // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound | |
832 | // regions just fine, showing `fn(&MyType)`. | |
833 | fn_sig_suggestion( | |
834 | tcx, | |
835 | tcx.fn_sig(assoc.def_id).skip_binder(), | |
5099ac24 | 836 | assoc.ident(tcx), |
1b1a35ee XL |
837 | tcx.predicates_of(assoc.def_id), |
838 | assoc, | |
839 | ) | |
840 | } | |
5099ac24 | 841 | ty::AssocKind::Type => format!("type {} = Type;", assoc.name), |
1b1a35ee XL |
842 | ty::AssocKind::Const => { |
843 | let ty = tcx.type_of(assoc.def_id); | |
844 | let val = expr::ty_kind_suggestion(ty).unwrap_or("value"); | |
5099ac24 | 845 | format!("const {}: {} = {};", assoc.name, ty, val) |
1b1a35ee XL |
846 | } |
847 | } | |
848 | } | |
849 | ||
136023e0 | 850 | /// Emit an error when encountering two or more variants in a transparent enum. |
5e7ed085 | 851 | fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) { |
1b1a35ee | 852 | let variant_spans: Vec<_> = adt |
5e7ed085 | 853 | .variants() |
1b1a35ee XL |
854 | .iter() |
855 | .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap()) | |
856 | .collect(); | |
5e7ed085 | 857 | let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),); |
04454e1e | 858 | let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}"); |
1b1a35ee XL |
859 | err.span_label(sp, &msg); |
860 | if let [start @ .., end] = &*variant_spans { | |
861 | for variant_span in start { | |
862 | err.span_label(*variant_span, ""); | |
863 | } | |
864 | err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did))); | |
865 | } | |
866 | err.emit(); | |
867 | } | |
868 | ||
136023e0 | 869 | /// Emit an error when encountering two or more non-zero-sized fields in a transparent |
1b1a35ee XL |
870 | /// enum. |
871 | fn bad_non_zero_sized_fields<'tcx>( | |
872 | tcx: TyCtxt<'tcx>, | |
5e7ed085 | 873 | adt: ty::AdtDef<'tcx>, |
1b1a35ee XL |
874 | field_count: usize, |
875 | field_spans: impl Iterator<Item = Span>, | |
876 | sp: Span, | |
877 | ) { | |
04454e1e | 878 | let msg = format!("needs at most one non-zero-sized field, but has {field_count}"); |
1b1a35ee XL |
879 | let mut err = struct_span_err!( |
880 | tcx.sess, | |
881 | sp, | |
882 | E0690, | |
883 | "{}transparent {} {}", | |
884 | if adt.is_enum() { "the variant of a " } else { "" }, | |
885 | adt.descr(), | |
886 | msg, | |
887 | ); | |
888 | err.span_label(sp, &msg); | |
889 | for sp in field_spans { | |
890 | err.span_label(sp, "this field is non-zero-sized"); | |
891 | } | |
892 | err.emit(); | |
893 | } | |
894 | ||
064997fb | 895 | fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, qpath: &hir::QPath<'_>, span: Span) { |
1b1a35ee XL |
896 | struct_span_err!( |
897 | tcx.sess, | |
898 | span, | |
899 | E0533, | |
064997fb | 900 | "expected unit struct, unit variant or constant, found {} `{}`", |
1b1a35ee | 901 | res.descr(), |
064997fb | 902 | rustc_hir_pretty::qpath_to_string(qpath), |
1b1a35ee XL |
903 | ) |
904 | .emit(); | |
905 | } | |
906 | ||
907 | /// Controls whether the arguments are tupled. This is used for the call | |
908 | /// operator. | |
909 | /// | |
910 | /// Tupling means that all call-side arguments are packed into a tuple and | |
911 | /// passed as a single parameter. For example, if tupling is enabled, this | |
912 | /// function: | |
04454e1e FG |
913 | /// ``` |
914 | /// fn f(x: (isize, isize)) {} | |
915 | /// ``` | |
1b1a35ee | 916 | /// Can be called as: |
04454e1e FG |
917 | /// ```ignore UNSOLVED (can this be done in user code?) |
918 | /// # fn f(x: (isize, isize)) {} | |
919 | /// f(1, 2); | |
920 | /// ``` | |
1b1a35ee | 921 | /// Instead of: |
04454e1e FG |
922 | /// ``` |
923 | /// # fn f(x: (isize, isize)) {} | |
924 | /// f((1, 2)); | |
925 | /// ``` | |
1b1a35ee XL |
926 | #[derive(Clone, Eq, PartialEq)] |
927 | enum TupleArgumentsFlag { | |
928 | DontTupleArguments, | |
929 | TupleArguments, | |
930 | } | |
931 | ||
17df50a5 | 932 | fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) { |
c295e0f8 | 933 | tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id)); |
1b1a35ee XL |
934 | } |
935 | ||
936 | fn fatally_break_rust(sess: &Session) { | |
937 | let handler = sess.diagnostic(); | |
938 | handler.span_bug_no_panic( | |
939 | MultiSpan::new(), | |
940 | "It looks like you're trying to break rust; would you like some ICE?", | |
941 | ); | |
942 | handler.note_without_error("the compiler expectedly panicked. this is a feature."); | |
943 | handler.note_without_error( | |
944 | "we would appreciate a joke overview: \ | |
945 | https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", | |
946 | ); | |
947 | handler.note_without_error(&format!( | |
948 | "rustc {} running on {}", | |
949 | option_env!("CFG_VERSION").unwrap_or("unknown_version"), | |
950 | config::host_triple(), | |
951 | )); | |
952 | } | |
953 | ||
954 | fn potentially_plural_count(count: usize, word: &str) -> String { | |
955 | format!("{} {}{}", count, word, pluralize!(count)) | |
956 | } | |
17df50a5 XL |
957 | |
958 | fn has_expected_num_generic_args<'tcx>( | |
959 | tcx: TyCtxt<'tcx>, | |
960 | trait_did: Option<DefId>, | |
961 | expected: usize, | |
962 | ) -> bool { | |
963 | trait_did.map_or(true, |trait_did| { | |
964 | let generics = tcx.generics_of(trait_did); | |
965 | generics.count() == expected + if generics.has_self { 1 } else { 0 } | |
966 | }) | |
967 | } |