X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=compiler%2Frustc_middle%2Fsrc%2Fty%2Fsty.rs;h=786cf4fb25199cd5b6c77f39d17fe2c7a9374778;hb=a53b604fea709deb2434319900fb34918cf72469;hp=028f9db368f3ae8678b39968cd11d531cf038b2d;hpb=4c793538d4c7b5ee28c5021635ae8526919ab98a;p=rust.git diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 028f9db368f..02a4df637d8 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -8,10 +8,13 @@ use crate::ty::fold::ValidateBoundVars; use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::InferTy::{self, *}; -use crate::ty::{self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable}; -use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS}; +use crate::ty::{ + self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitor, +}; +use crate::ty::{DelaySpanBugEmitted, List, ParamEnv}; use polonius_engine::Atom; use rustc_data_structures::captures::Captures; +use rustc_data_structures::intern::Interned; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; @@ -21,8 +24,9 @@ use rustc_target::spec::abi; use std::borrow::Cow; use std::cmp::Ordering; +use std::fmt; use std::marker::PhantomData; -use std::ops::Range; +use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] @@ -114,7 +118,7 @@ pub enum TyKind<'tcx> { Str, /// An array with the given length. Written as `[T; N]`. - Array(Ty<'tcx>, &'tcx ty::Const<'tcx>), + Array(Ty<'tcx>, ty::Const<'tcx>), /// The pointee of an array slice. Written as `[T]`. Slice(Ty<'tcx>), @@ -196,8 +200,7 @@ pub enum TyKind<'tcx> { Never, /// A tuple type. For example, `(i32, bool)`. - /// Use `TyS::tuple_fields` to iterate over the field types. - Tuple(SubstsRef<'tcx>), + Tuple(&'tcx List>), /// The projection of an associated type. For example, /// `>::N`. @@ -209,8 +212,10 @@ pub enum TyKind<'tcx> { /// * the `impl Trait` ast::Ty node, /// * or the `type Foo = impl Trait` declaration /// - /// For RTIT the substitutions are for the generics of the function, + /// For RPIT the substitutions are for the generics of the function, /// while for TAIT it is used for the generic parameters of the alias. + /// + /// During codegen, `tcx.type_of(def_id)` can be used to get the underlying type. Opaque(DefId, SubstsRef<'tcx>), /// A type parameter; for example, `T` in `fn f(x: T) {}`. @@ -280,7 +285,7 @@ pub fn article(&self) -> &'static str { /// in scope on the function that defined the closure, /// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This /// is rather hackily encoded via a scalar type. See -/// `TyS::to_opt_closure_kind` for details. +/// `Ty::to_opt_closure_kind` for details. /// - CS represents the *closure signature*, representing as a `fn()` /// type. For example, `fn(u32, u32) -> u32` would mean that the closure /// implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait @@ -1389,7 +1394,24 @@ pub fn for_def(def: &ty::GenericParamDef) -> ParamConst { } } -pub type Region<'tcx> = &'tcx RegionKind; +/// Use this rather than `TyKind`, whenever possible. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] +#[cfg_attr(not(bootstrap), rustc_pass_by_value)] +pub struct Region<'tcx>(pub Interned<'tcx, RegionKind>); + +impl<'tcx> Deref for Region<'tcx> { + type Target = RegionKind; + + fn deref(&self) -> &RegionKind { + &self.0.0 + } +} + +impl<'tcx> fmt::Debug for Region<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.kind()) + } +} /// Representation of regions. Note that the NLL checker uses a distinct /// representation of regions. For this reason, it internally replaces all the @@ -1397,6 +1419,9 @@ pub fn for_def(def: &ty::GenericParamDef) -> ParamConst { /// to index into internal NLL data structures. See `rustc_const_eval::borrow_check` /// module for more information. /// +/// Note: operations are on the wrapper `Region` type, which is interned, +/// rather than this type. +/// /// ## The Region lattice within a given function /// /// In general, the region lattice looks like @@ -1653,40 +1678,59 @@ pub fn item_def_id(&self) -> DefId { } /// Region utilities -impl RegionKind { +impl<'tcx> Region<'tcx> { + pub fn kind(self) -> RegionKind { + *self.0.0 + } + /// Is this region named by the user? - pub fn has_name(&self) -> bool { + pub fn has_name(self) -> bool { match *self { - RegionKind::ReEarlyBound(ebr) => ebr.has_name(), - RegionKind::ReLateBound(_, br) => br.kind.is_named(), - RegionKind::ReFree(fr) => fr.bound_region.is_named(), - RegionKind::ReStatic => true, - RegionKind::ReVar(..) => false, - RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(), - RegionKind::ReEmpty(_) => false, - RegionKind::ReErased => false, + ty::ReEarlyBound(ebr) => ebr.has_name(), + ty::ReLateBound(_, br) => br.kind.is_named(), + ty::ReFree(fr) => fr.bound_region.is_named(), + ty::ReStatic => true, + ty::ReVar(..) => false, + ty::RePlaceholder(placeholder) => placeholder.name.is_named(), + ty::ReEmpty(_) => false, + ty::ReErased => false, } } #[inline] - pub fn is_late_bound(&self) -> bool { + pub fn is_static(self) -> bool { + matches!(*self, ty::ReStatic) + } + + #[inline] + pub fn is_erased(self) -> bool { + matches!(*self, ty::ReErased) + } + + #[inline] + pub fn is_late_bound(self) -> bool { matches!(*self, ty::ReLateBound(..)) } #[inline] - pub fn is_placeholder(&self) -> bool { + pub fn is_placeholder(self) -> bool { matches!(*self, ty::RePlaceholder(..)) } #[inline] - pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool { + pub fn is_empty(self) -> bool { + matches!(*self, ty::ReEmpty(..)) + } + + #[inline] + pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool { match *self { ty::ReLateBound(debruijn, _) => debruijn >= index, _ => false, } } - pub fn type_flags(&self) -> TypeFlags { + pub fn type_flags(self) -> TypeFlags { let mut flags = TypeFlags::empty(); match *self { @@ -1744,8 +1788,8 @@ pub fn type_flags(&self) -> TypeFlags { /// of the impl, and for all the other highlighted regions, it /// would return the `DefId` of the function. In other cases (not shown), this /// function might return the `DefId` of a closure. - pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_>) -> DefId { - match self { + pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId { + match *self { ty::ReEarlyBound(br) => tcx.parent(br.def_id).unwrap(), ty::ReFree(fr) => fr.scope, _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self), @@ -1754,19 +1798,19 @@ pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_>) -> DefId { } /// Type utilities -impl<'tcx> TyS<'tcx> { +impl<'tcx> Ty<'tcx> { #[inline(always)] - pub fn kind(&self) -> &TyKind<'tcx> { - &self.kind + pub fn kind(self) -> &'tcx TyKind<'tcx> { + &self.0.0.kind } #[inline(always)] - pub fn flags(&self) -> TypeFlags { - self.flags + pub fn flags(self) -> TypeFlags { + self.0.0.flags } #[inline] - pub fn is_unit(&self) -> bool { + pub fn is_unit(self) -> bool { match self.kind() { Tuple(ref tys) => tys.is_empty(), _ => false, @@ -1774,32 +1818,32 @@ pub fn is_unit(&self) -> bool { } #[inline] - pub fn is_never(&self) -> bool { + pub fn is_never(self) -> bool { matches!(self.kind(), Never) } #[inline] - pub fn is_primitive(&self) -> bool { + pub fn is_primitive(self) -> bool { self.kind().is_primitive() } #[inline] - pub fn is_adt(&self) -> bool { + pub fn is_adt(self) -> bool { matches!(self.kind(), Adt(..)) } #[inline] - pub fn is_ref(&self) -> bool { + pub fn is_ref(self) -> bool { matches!(self.kind(), Ref(..)) } #[inline] - pub fn is_ty_var(&self) -> bool { + pub fn is_ty_var(self) -> bool { matches!(self.kind(), Infer(TyVar(_))) } #[inline] - pub fn ty_vid(&self) -> Option { + pub fn ty_vid(self) -> Option { match self.kind() { &Infer(TyVar(vid)) => Some(vid), _ => None, @@ -1807,28 +1851,28 @@ pub fn ty_vid(&self) -> Option { } #[inline] - pub fn is_ty_infer(&self) -> bool { + pub fn is_ty_infer(self) -> bool { matches!(self.kind(), Infer(_)) } #[inline] - pub fn is_phantom_data(&self) -> bool { + pub fn is_phantom_data(self) -> bool { if let Adt(def, _) = self.kind() { def.is_phantom_data() } else { false } } #[inline] - pub fn is_bool(&self) -> bool { + pub fn is_bool(self) -> bool { *self.kind() == Bool } /// Returns `true` if this type is a `str`. #[inline] - pub fn is_str(&self) -> bool { + pub fn is_str(self) -> bool { *self.kind() == Str } #[inline] - pub fn is_param(&self, index: u32) -> bool { + pub fn is_param(self, index: u32) -> bool { match self.kind() { ty::Param(ref data) => data.index == index, _ => false, @@ -1836,7 +1880,7 @@ pub fn is_param(&self, index: u32) -> bool { } #[inline] - pub fn is_slice(&self) -> bool { + pub fn is_slice(self) -> bool { match self.kind() { RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_) | Str), _ => false, @@ -1844,34 +1888,27 @@ pub fn is_slice(&self) -> bool { } #[inline] - pub fn is_array(&self) -> bool { + pub fn is_array(self) -> bool { matches!(self.kind(), Array(..)) } #[inline] - pub fn is_simd(&self) -> bool { + pub fn is_simd(self) -> bool { match self.kind() { Adt(def, _) => def.repr.simd(), _ => false, } } - pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind() { - Array(ty, _) | Slice(ty) => ty, + Array(ty, _) | Slice(ty) => *ty, Str => tcx.types.u8, _ => bug!("`sequence_element_type` called on non-sequence value: {}", self), } } - pub fn expect_opaque_type(&self) -> ty::OpaqueTypeKey<'tcx> { - match *self.kind() { - Opaque(def_id, substs) => ty::OpaqueTypeKey { def_id, substs }, - _ => bug!("`expect_opaque_type` called on non-opaque type: {}", self), - } - } - - pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { + pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { match self.kind() { Adt(def, substs) => { assert!(def.repr.simd(), "`simd_size_and_type` called on non-SIMD type"); @@ -1886,7 +1923,7 @@ pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { // The way we evaluate the `N` in `[T; N]` here only works since we use // `simd_size_and_type` post-monomorphization. It will probably start to ICE // if we use it in generic code. See the `simd-array-trait` ui test. - (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty) + (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, *f0_elem_ty) } // Otherwise, the fields of this Adt are the SIMD components (and we assume they // all have the same type). @@ -1898,12 +1935,12 @@ pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { } #[inline] - pub fn is_region_ptr(&self) -> bool { + pub fn is_region_ptr(self) -> bool { matches!(self.kind(), Ref(..)) } #[inline] - pub fn is_mutable_ptr(&self) -> bool { + pub fn is_mutable_ptr(self) -> bool { matches!( self.kind(), RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. }) @@ -1913,7 +1950,7 @@ pub fn is_mutable_ptr(&self) -> bool { /// Get the mutability of the reference or `None` when not a reference #[inline] - pub fn ref_mutability(&self) -> Option { + pub fn ref_mutability(self) -> Option { match self.kind() { Ref(_, _, mutability) => Some(*mutability), _ => None, @@ -1921,18 +1958,18 @@ pub fn ref_mutability(&self) -> Option { } #[inline] - pub fn is_unsafe_ptr(&self) -> bool { + pub fn is_unsafe_ptr(self) -> bool { matches!(self.kind(), RawPtr(_)) } /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer). #[inline] - pub fn is_any_ptr(&self) -> bool { + pub fn is_any_ptr(self) -> bool { self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr() } #[inline] - pub fn is_box(&self) -> bool { + pub fn is_box(self) -> bool { match self.kind() { Adt(def, _) => def.is_box(), _ => false, @@ -1940,7 +1977,7 @@ pub fn is_box(&self) -> bool { } /// Panics if called on any type other than `Box`. - pub fn boxed_ty(&self) -> Ty<'tcx> { + pub fn boxed_ty(self) -> Ty<'tcx> { match self.kind() { Adt(def, substs) if def.is_box() => substs.type_at(0), _ => bug!("`boxed_ty` is called on non-box type {:?}", self), @@ -1951,7 +1988,7 @@ pub fn boxed_ty(&self) -> Ty<'tcx> { /// (A RawPtr is scalar because it represents a non-managed pointer, so its /// contents are abstract to rustc.) #[inline] - pub fn is_scalar(&self) -> bool { + pub fn is_scalar(self) -> bool { matches!( self.kind(), Bool | Char @@ -1967,99 +2004,117 @@ pub fn is_scalar(&self) -> bool { /// Returns `true` if this type is a floating point type. #[inline] - pub fn is_floating_point(&self) -> bool { + pub fn is_floating_point(self) -> bool { matches!(self.kind(), Float(_) | Infer(FloatVar(_))) } #[inline] - pub fn is_trait(&self) -> bool { + pub fn is_trait(self) -> bool { matches!(self.kind(), Dynamic(..)) } #[inline] - pub fn is_enum(&self) -> bool { + pub fn is_enum(self) -> bool { matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum()) } #[inline] - pub fn is_union(&self) -> bool { + pub fn is_union(self) -> bool { matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union()) } #[inline] - pub fn is_closure(&self) -> bool { + pub fn is_closure(self) -> bool { matches!(self.kind(), Closure(..)) } #[inline] - pub fn is_generator(&self) -> bool { + pub fn is_generator(self) -> bool { matches!(self.kind(), Generator(..)) } #[inline] - pub fn is_integral(&self) -> bool { + pub fn is_integral(self) -> bool { matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_)) } #[inline] - pub fn is_fresh_ty(&self) -> bool { + pub fn is_fresh_ty(self) -> bool { matches!(self.kind(), Infer(FreshTy(_))) } #[inline] - pub fn is_fresh(&self) -> bool { + pub fn is_fresh(self) -> bool { matches!(self.kind(), Infer(FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_))) } #[inline] - pub fn is_char(&self) -> bool { + pub fn is_char(self) -> bool { matches!(self.kind(), Char) } #[inline] - pub fn is_numeric(&self) -> bool { + pub fn is_numeric(self) -> bool { self.is_integral() || self.is_floating_point() } #[inline] - pub fn is_signed(&self) -> bool { + pub fn is_signed(self) -> bool { matches!(self.kind(), Int(_)) } #[inline] - pub fn is_ptr_sized_integral(&self) -> bool { + pub fn is_ptr_sized_integral(self) -> bool { matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize)) } #[inline] - pub fn has_concrete_skeleton(&self) -> bool { + pub fn has_concrete_skeleton(self) -> bool { !matches!(self.kind(), Param(_) | Infer(_) | Error(_)) } + /// Checks whether a type recursively contains another type + /// + /// Example: `Option<()>` contains `()` + pub fn contains(self, other: Ty<'tcx>) -> bool { + struct ContainsTyVisitor<'tcx>(Ty<'tcx>); + + impl<'tcx> TypeVisitor<'tcx> for ContainsTyVisitor<'tcx> { + type BreakTy = (); + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + if self.0 == t { ControlFlow::BREAK } else { t.super_visit_with(self) } + } + } + + let cf = self.visit_with(&mut ContainsTyVisitor(other)); + cf.is_break() + } + /// Returns the type and mutability of `*ty`. /// /// The parameter `explicit` indicates if this is an *explicit* dereference. /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. - pub fn builtin_deref(&self, explicit: bool) -> Option> { + pub fn builtin_deref(self, explicit: bool) -> Option> { match self.kind() { Adt(def, _) if def.is_box() => { Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not }) } - Ref(_, ty, mutbl) => Some(TypeAndMut { ty, mutbl: *mutbl }), + Ref(_, ty, mutbl) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }), RawPtr(mt) if explicit => Some(*mt), _ => None, } } /// Returns the type of `ty[i]`. - pub fn builtin_index(&self) -> Option> { + pub fn builtin_index(self) -> Option> { match self.kind() { - Array(ty, _) | Slice(ty) => Some(ty), + Array(ty, _) | Slice(ty) => Some(*ty), _ => None, } } - pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { + pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { match self.kind() { FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs), FnPtr(f) => *f, @@ -2075,22 +2130,22 @@ pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { } #[inline] - pub fn is_fn(&self) -> bool { + pub fn is_fn(self) -> bool { matches!(self.kind(), FnDef(..) | FnPtr(_)) } #[inline] - pub fn is_fn_ptr(&self) -> bool { + pub fn is_fn_ptr(self) -> bool { matches!(self.kind(), FnPtr(_)) } #[inline] - pub fn is_impl_trait(&self) -> bool { + pub fn is_impl_trait(self) -> bool { matches!(self.kind(), Opaque(..)) } #[inline] - pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> { + pub fn ty_adt_def(self) -> Option<&'tcx AdtDef> { match self.kind() { Adt(adt, _) => Some(adt), _ => None, @@ -2099,18 +2154,9 @@ pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> { /// Iterates over tuple fields. /// Panics when called on anything but a tuple. - pub fn tuple_fields(&self) -> impl DoubleEndedIterator> { - match self.kind() { - Tuple(substs) => substs.iter().map(|field| field.expect_ty()), - _ => bug!("tuple_fields called on non-tuple"), - } - } - - /// Get the `i`-th element of a tuple. - /// Panics when called on anything but a tuple. - pub fn tuple_element_ty(&self, i: usize) -> Option> { + pub fn tuple_fields(self) -> &'tcx List> { match self.kind() { - Tuple(substs) => substs.iter().nth(i).map(|field| field.expect_ty()), + Tuple(substs) => substs, _ => bug!("tuple_fields called on non-tuple"), } } @@ -2119,7 +2165,7 @@ pub fn tuple_element_ty(&self, i: usize) -> Option> { // // FIXME: This requires the optimized MIR in the case of generators. #[inline] - pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option> { + pub fn variant_range(self, tcx: TyCtxt<'tcx>) -> Option> { match self.kind() { TyKind::Adt(adt, _) => Some(adt.variant_range()), TyKind::Generator(def_id, substs, _) => { @@ -2135,7 +2181,7 @@ pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option> { // FIXME: This requires the optimized MIR in the case of generators. #[inline] pub fn discriminant_for_variant( - &self, + self, tcx: TyCtxt<'tcx>, variant_index: VariantIdx, ) -> Option> { @@ -2156,7 +2202,7 @@ pub fn discriminant_for_variant( } /// Returns the type of the discriminant of this type. - pub fn discriminant_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self.kind() { ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx), ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), @@ -2200,7 +2246,7 @@ pub fn discriminant_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { /// Returns the type of metadata for (potentially fat) pointers to this type. pub fn ptr_metadata_ty( - &'tcx self, + self, tcx: TyCtxt<'tcx>, normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>, ) -> Ty<'tcx> { @@ -2261,7 +2307,7 @@ pub fn ptr_metadata_ty( /// to represent the closure kind, because it has not yet been /// inferred. Once upvar inference (in `rustc_typeck/src/check/upvar.rs`) /// is complete, that type variable will be unified. - pub fn to_opt_closure_kind(&self) -> Option { + pub fn to_opt_closure_kind(self) -> Option { match self.kind() { Int(int_ty) => match int_ty { ty::IntTy::I8 => Some(ty::ClosureKind::Fn), @@ -2290,7 +2336,7 @@ pub fn to_opt_closure_kind(&self) -> Option { /// bound such as `[_]: Copy`. A function with such a bound obviously never /// can be called, but that doesn't mean it shouldn't typecheck. This is why /// this method doesn't return `Option`. - pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool { + pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool { match self.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) @@ -2311,7 +2357,7 @@ pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool { ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false, - ty::Tuple(tys) => tys.iter().all(|ty| ty.expect_ty().is_trivially_sized(tcx)), + ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)), ty::Adt(def, _substs) => def.sized_constraint(tcx).is_empty(),