diff options
Diffstat (limited to 'compiler/rustc_middle/src/ty')
| -rw-r--r-- | compiler/rustc_middle/src/ty/codec.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/consts.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/consts/int.rs | 92 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/consts/valtree.rs | 19 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/diagnostics.rs | 398 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/error.rs | 59 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/layout.rs | 53 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/list.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/query.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/sty.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/util.rs | 14 |
12 files changed, 319 insertions, 349 deletions
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 7fcc46cc7c2..23c377651cc 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -453,9 +453,6 @@ macro_rules! impl_arena_allocatable_decoder { } } }; - ([$ignore:ident $(, $attrs:ident)*]$args:tt) => { - impl_arena_allocatable_decoder!([$($attrs),*]$args); - }; } macro_rules! impl_arena_allocatable_decoders { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 4b7c1d44cea..7af7eb4f5ec 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -44,10 +44,12 @@ pub struct ConstS<'tcx> { static_assert_size!(ConstS<'_>, 48); impl<'tcx> Const<'tcx> { + #[inline] pub fn ty(self) -> Ty<'tcx> { self.0.ty } + #[inline] pub fn val(self) -> ConstKind<'tcx> { self.0.val } diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 72623ba54ee..a3ce674c115 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -237,6 +237,98 @@ impl ScalarInt { pub fn try_to_machine_usize<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Result<u64, Size> { Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64) } + + /// Tries to convert the `ScalarInt` to an unsigned integer of the given size. + /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the + /// `ScalarInt`s size in that case. + #[inline] + pub fn try_to_uint(self, size: Size) -> Result<u128, Size> { + self.to_bits(size) + } + + // Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt` + // in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in + // that case. + #[inline] + pub fn try_to_u8(self) -> Result<u8, Size> { + self.to_bits(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap()) + } + + /// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt` + /// in not equal to `Size { raw: 2 }` and returns the `size` value of the `ScalarInt` in + /// that case. + #[inline] + pub fn try_to_u16(self) -> Result<u16, Size> { + self.to_bits(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap()) + } + + /// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt` + /// in not equal to `Size { raw: 4 }` and returns the `size` value of the `ScalarInt` in + /// that case. + #[inline] + pub fn try_to_u32(self) -> Result<u32, Size> { + self.to_bits(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap()) + } + + /// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt` + /// in not equal to `Size { raw: 8 }` and returns the `size` value of the `ScalarInt` in + /// that case. + #[inline] + pub fn try_to_u64(self) -> Result<u64, Size> { + self.to_bits(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap()) + } + + /// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt` + /// in not equal to `Size { raw: 16 }` and returns the `size` value of the `ScalarInt` in + /// that case. + #[inline] + pub fn try_to_u128(self) -> Result<u128, Size> { + self.to_bits(Size::from_bits(128)) + } + + /// Tries to convert the `ScalarInt` to a signed integer of the given size. + /// Fails if the size of the `ScalarInt` is unequal to `size` and returns the + /// `ScalarInt`s size in that case. + #[inline] + pub fn try_to_int(self, size: Size) -> Result<i128, Size> { + let b = self.to_bits(size)?; + Ok(size.sign_extend(b) as i128) + } + + /// Tries to convert the `ScalarInt` to i8. + /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 1 }` + /// and returns the `ScalarInt`s size in that case. + pub fn try_to_i8(self) -> Result<i8, Size> { + self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap()) + } + + /// Tries to convert the `ScalarInt` to i16. + /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 2 }` + /// and returns the `ScalarInt`s size in that case. + pub fn try_to_i16(self) -> Result<i16, Size> { + self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap()) + } + + /// Tries to convert the `ScalarInt` to i32. + /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 4 }` + /// and returns the `ScalarInt`s size in that case. + pub fn try_to_i32(self) -> Result<i32, Size> { + self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap()) + } + + /// Tries to convert the `ScalarInt` to i64. + /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 8 }` + /// and returns the `ScalarInt`s size in that case. + pub fn try_to_i64(self) -> Result<i64, Size> { + self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap()) + } + + /// Tries to convert the `ScalarInt` to i128. + /// Fails if the size of the `ScalarInt` is unequal to `Size { raw: 16 }` + /// and returns the `ScalarInt`s size in that case. + pub fn try_to_i128(self) -> Result<i128, Size> { + self.try_to_int(Size::from_bits(128)).map(|v| i128::try_from(v).unwrap()) + } } macro_rules! from { diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 195760c0590..418848f69d7 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -20,6 +20,9 @@ pub enum ValTree<'tcx> { /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values /// of these types have the same representation. Leaf(ScalarInt), + + //SliceOrStr(ValSlice<'tcx>), + // dont use SliceOrStr for now /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by /// listing their fields' values in order. /// Enums are represented by storing their discriminant as a field, followed by all @@ -31,4 +34,20 @@ impl<'tcx> ValTree<'tcx> { pub fn zst() -> Self { Self::Branch(&[]) } + + #[inline] + pub fn unwrap_leaf(self) -> ScalarInt { + match self { + Self::Leaf(s) => s, + _ => bug!("expected leaf, got {:?}", self), + } + } + + #[inline] + pub fn unwrap_branch(self) -> &'tcx [Self] { + match self { + Self::Branch(branch) => branch, + _ => bug!("expected branch, got {:?}", self), + } + } } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 3b044b19259..f53dc0000ca 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,15 +3,15 @@ use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::TyKind::*; use crate::ty::{ - ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy, - ProjectionTy, Term, Ty, TyCtxt, TypeAndMut, + ConstKind, DefIdTree, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, + InferTy, ProjectionTy, Term, Ty, TyCtxt, TypeAndMut, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; +use rustc_hir::WherePredicate; use rustc_span::Span; impl<'tcx> IntoDiagnosticArg for Ty<'tcx> { @@ -74,10 +74,10 @@ impl<'tcx> Ty<'tcx> { } /// Whether the type can be safely suggested during error recovery. - pub fn is_suggestable(self) -> bool { - fn generic_arg_is_suggestible(arg: GenericArg<'_>) -> bool { + pub fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool { + fn generic_arg_is_suggestible<'tcx>(arg: GenericArg<'tcx>, tcx: TyCtxt<'tcx>) -> bool { match arg.unpack() { - GenericArgKind::Type(ty) => ty.is_suggestable(), + GenericArgKind::Type(ty) => ty.is_suggestable(tcx), GenericArgKind::Const(c) => const_is_suggestable(c.val()), _ => true, } @@ -99,8 +99,7 @@ impl<'tcx> Ty<'tcx> { // temporary, so I'll leave this as a fixme. match self.kind() { - Opaque(..) - | FnDef(..) + FnDef(..) | Closure(..) | Infer(..) | Generator(..) @@ -108,27 +107,38 @@ impl<'tcx> Ty<'tcx> { | Bound(_, _) | Placeholder(_) | Error(_) => false, + Opaque(did, substs) => { + let parent = tcx.parent(*did).expect("opaque types always have a parent"); + if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = tcx.def_kind(parent) + && let Opaque(parent_did, _) = tcx.type_of(parent).kind() + && parent_did == did + { + substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) + } else { + false + } + } Dynamic(dty, _) => dty.iter().all(|pred| match pred.skip_binder() { ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => { - substs.iter().all(generic_arg_is_suggestible) + substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) } ExistentialPredicate::Projection(ExistentialProjection { substs, term, .. }) => { let term_is_suggestable = match term { - Term::Ty(ty) => ty.is_suggestable(), + Term::Ty(ty) => ty.is_suggestable(tcx), Term::Const(c) => const_is_suggestable(c.val()), }; - term_is_suggestable && substs.iter().all(generic_arg_is_suggestible) + term_is_suggestable && substs.iter().all(|a| generic_arg_is_suggestible(a, tcx)) } _ => true, }), Projection(ProjectionTy { substs: args, .. }) | Adt(_, args) => { - args.iter().all(generic_arg_is_suggestible) + args.iter().all(|a| generic_arg_is_suggestible(a, tcx)) } - Tuple(args) => args.iter().all(|ty| ty.is_suggestable()), - Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(), - Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val()), + Tuple(args) => args.iter().all(|ty| ty.is_suggestable(tcx)), + Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(tcx), + Array(ty, c) => ty.is_suggestable(tcx) && const_is_suggestable(c.val()), _ => true, } } @@ -146,13 +156,13 @@ pub fn suggest_arbitrary_trait_bound( _ => {} } // Suggest a where clause bound for a non-type parameter. - let (action, prefix) = if generics.where_clause.predicates.is_empty() { - ("introducing a", " where ") - } else { + let (action, prefix) = if generics.has_where_clause { ("extending the", ", ") + } else { + ("introducing a", " where ") }; err.span_suggestion_verbose( - generics.where_clause.tail_span_for_suggestion(), + generics.tail_span_for_predicate_suggestion(), &format!( "consider {} `where` bound, but there might be an alternative better way to express \ this requirement", @@ -173,104 +183,37 @@ enum SuggestChangingConstraintsMessage<'a> { } fn suggest_removing_unsized_bound( + tcx: TyCtxt<'_>, generics: &hir::Generics<'_>, suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>, - param_name: &str, param: &hir::GenericParam<'_>, def_id: Option<DefId>, ) { // See if there's a `?Sized` bound that can be removed to suggest that. // First look at the `where` clause because we can have `where T: ?Sized`, // then look at params. - for (where_pos, predicate) in generics.where_clause.predicates.iter().enumerate() { - match predicate { - WherePredicate::BoundPredicate(WhereBoundPredicate { - bounded_ty: - hir::Ty { - kind: - hir::TyKind::Path(hir::QPath::Resolved( - None, - hir::Path { - segments: [segment], - res: hir::def::Res::Def(hir::def::DefKind::TyParam, _), - .. - }, - )), - .. - }, - bounds, - span, - .. - }) if segment.ident.as_str() == param_name => { - for (pos, bound) in bounds.iter().enumerate() { - match bound { - hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) - if poly.trait_ref.trait_def_id() == def_id => {} - _ => continue, - } - let sp = match ( - bounds.len(), - pos, - generics.where_clause.predicates.len(), - where_pos, - ) { - // where T: ?Sized - // ^^^^^^^^^^^^^^^ - (1, _, 1, _) => generics.where_clause.span, - // where Foo: Bar, T: ?Sized, - // ^^^^^^^^^^^ - (1, _, len, pos) if pos == len - 1 => generics.where_clause.predicates - [pos - 1] - .span() - .shrink_to_hi() - .to(*span), - // where T: ?Sized, Foo: Bar, - // ^^^^^^^^^^^ - (1, _, _, pos) => { - span.until(generics.where_clause.predicates[pos + 1].span()) - } - // where T: ?Sized + Bar, Foo: Bar, - // ^^^^^^^^^ - (_, 0, _, _) => bound.span().to(bounds[1].span().shrink_to_lo()), - // where T: Bar + ?Sized, Foo: Bar, - // ^^^^^^^^^ - (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()), - }; + let param_def_id = tcx.hir().local_def_id(param.hir_id); + for (where_pos, predicate) in generics.predicates.iter().enumerate() { + let WherePredicate::BoundPredicate(predicate) = predicate else { + continue; + }; + if !predicate.is_param_bound(param_def_id.to_def_id()) { + continue; + }; - suggestions.push(( - sp, - String::new(), - SuggestChangingConstraintsMessage::RemovingQSized, - )); - } - } - _ => {} - } - } - for (pos, bound) in param.bounds.iter().enumerate() { - match bound { - hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) - if poly.trait_ref.trait_def_id() == def_id => - { - let sp = match (param.bounds.len(), pos) { - // T: ?Sized, - // ^^^^^^^^ - (1, _) => param.span.shrink_to_hi().to(bound.span()), - // T: ?Sized + Bar, - // ^^^^^^^^^ - (_, 0) => bound.span().to(param.bounds[1].span().shrink_to_lo()), - // T: Bar + ?Sized, - // ^^^^^^^^^ - (_, pos) => param.bounds[pos - 1].span().shrink_to_hi().to(bound.span()), - }; - - suggestions.push(( - sp, - String::new(), - SuggestChangingConstraintsMessage::RemovingQSized, - )); + for (pos, bound) in predicate.bounds.iter().enumerate() { + let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else { + continue; + }; + if poly.trait_ref.trait_def_id() != def_id { + continue; } - _ => {} + let sp = generics.span_for_bound_removal(where_pos, pos); + suggestions.push(( + sp, + String::new(), + SuggestChangingConstraintsMessage::RemovingQSized, + )); } } } @@ -321,13 +264,7 @@ pub fn suggest_constraining_type_params<'a>( param.span, &format!("this type parameter needs to be `{}`", constraint), ); - suggest_removing_unsized_bound( - generics, - &mut suggestions, - param_name, - param, - def_id, - ); + suggest_removing_unsized_bound(tcx, generics, &mut suggestions, param, def_id); } } @@ -348,76 +285,45 @@ pub fn suggest_constraining_type_params<'a>( )) }; - if param_name.starts_with("impl ") { - // If there's an `impl Trait` used in argument position, suggest - // restricting it: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // replace with: `impl Foo + Bar` - - // `impl Trait` must have at least one trait in the list - let bound_list_non_empty = true; - - suggest_restrict(param.span.shrink_to_hi(), bound_list_non_empty); + // When the type parameter has been provided bounds + // + // Message: + // fn foo<T>(t: T) where T: Foo { ... } + // ^^^^^^ + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion: + // fn foo<T>(t: T) where T: Foo { ... } + // ^ + // | + // replace with: ` + Bar` + // + // Or, if user has provided some bounds, suggest restricting them: + // + // fn foo<T: Foo>(t: T) { ... } + // --- + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion for tools in this case is: + // + // fn foo<T: Foo>(t: T) { ... } + // -- + // | + // replace with: `T: Bar +` + let param_def_id = tcx.hir().local_def_id(param.hir_id); + if let Some(span) = generics.bounds_span_for_suggestions(param_def_id) { + suggest_restrict(span, true); continue; } - if generics.where_clause.predicates.is_empty() - // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the - // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`. - && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) - { - if let Some(span) = param.bounds_span_for_suggestions() { - // If user has provided some bounds, suggest restricting them: - // - // fn foo<T: Foo>(t: T) { ... } - // --- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo<T: Foo>(t: T) { ... } - // -- - // | - // replace with: `T: Bar +` - - // `bounds_span_for_suggestions` returns `None` if the list is empty - let bound_list_non_empty = true; - - suggest_restrict(span, bound_list_non_empty); - } else { - let (colon, span) = match param.colon_span_for_suggestions(tcx.sess.source_map()) { - // If there is already a colon after generic, do not suggest adding it again - Some(sp) => ("", sp.shrink_to_hi()), - None => (":", param.span.shrink_to_hi()), - }; - - // If user hasn't provided any bounds, suggest adding a new one: - // - // fn foo<T>(t: T) { ... } - // - help: consider restricting this type parameter with `T: Foo` - suggestions.push(( - span, - format!("{colon} {constraint}"), - SuggestChangingConstraintsMessage::RestrictType { ty: param_name }, - )); - } - } else { + if generics.has_where_clause { // This part is a bit tricky, because using the `where` clause user can // provide zero, one or many bounds for the same type parameter, so we // have following cases to consider: // - // 1) When the type parameter has been provided zero bounds + // When the type parameter has been provided zero bounds // // Message: // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } @@ -426,95 +332,59 @@ pub fn suggest_constraining_type_params<'a>( // Suggestion: // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } // - insert: `, X: Bar` - // - // - // 2) When the type parameter has been provided one bound - // - // Message: - // fn foo<T>(t: T) where T: Foo { ... } - // ^^^^^^ - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion: - // fn foo<T>(t: T) where T: Foo { ... } - // ^^ - // | - // replace with: `T: Bar +` - // - // - // 3) When the type parameter has been provided many bounds - // - // Message: - // fn foo<T>(t: T) where T: Foo, T: Bar {... } - // - help: consider further restricting this type parameter with `where T: Zar` - // - // Suggestion: - // fn foo<T>(t: T) where T: Foo, T: Bar {... } - // - insert: `, T: Zar` - // - // Additionally, there may be no `where` clause whatsoever in the case that this was - // reached because the generic parameter has a default: - // - // Message: - // trait Foo<T=()> {... } - // - help: consider further restricting this type parameter with `where T: Zar` - // - // Suggestion: - // trait Foo<T=()> where T: Zar {... } - // - insert: `where T: Zar` - - if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) - && generics.where_clause.predicates.len() == 0 - { - // Suggest a bound, but there is no existing `where` clause *and* the type param has a - // default (`<T=Foo>`), so we suggest adding `where T: Bar`. - suggestions.push(( - generics.where_clause.tail_span_for_suggestion(), - format!(" where {}: {}", param_name, constraint), - SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name }, - )); - } else { - let mut param_spans = Vec::new(); - let mut non_empty = false; - - for predicate in generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(WhereBoundPredicate { - span, - bounded_ty, - bounds, - .. - }) = predicate - { - if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { - if let Some(segment) = path.segments.first() { - if segment.ident.to_string() == param_name { - non_empty = !bounds.is_empty(); - - param_spans.push(span); - } - } - } - } - } + suggestions.push(( + generics.tail_span_for_predicate_suggestion(), + constraints + .iter() + .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint)) + .collect::<String>(), + SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name }, + )); + continue; + } - match param_spans[..] { - [¶m_span] => suggest_restrict(param_span.shrink_to_hi(), non_empty), - _ => { - suggestions.push(( - generics.where_clause.tail_span_for_suggestion(), - constraints - .iter() - .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint)) - .collect::<String>(), - SuggestChangingConstraintsMessage::RestrictTypeFurther { - ty: param_name, - }, - )); - } - } - } + // Additionally, there may be no `where` clause but the generic parameter has a default: + // + // Message: + // trait Foo<T=()> {... } + // - help: consider further restricting this type parameter with `where T: Zar` + // + // Suggestion: + // trait Foo<T=()> {... } + // - insert: `where T: Zar` + if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) { + // Suggest a bound, but there is no existing `where` clause *and* the type param has a + // default (`<T=Foo>`), so we suggest adding `where T: Bar`. + suggestions.push(( + generics.tail_span_for_predicate_suggestion(), + format!(" where {}: {}", param_name, constraint), + SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name }, + )); + continue; } + + // If user has provided a colon, don't suggest adding another: + // + // fn foo<T:>(t: T) { ... } + // - insert: consider restricting this type parameter with `T: Foo` + if let Some(colon_span) = param.colon_span { + suggestions.push(( + colon_span.shrink_to_hi(), + format!(" {}", constraint), + SuggestChangingConstraintsMessage::RestrictType { ty: param_name }, + )); + continue; + } + + // If user hasn't provided any bounds, suggest adding a new one: + // + // fn foo<T>(t: T) { ... } + // - help: consider restricting this type parameter with `T: Foo` + suggestions.push(( + param.span.shrink_to_hi(), + format!(": {}", constraint), + SuggestChangingConstraintsMessage::RestrictType { ty: param_name }, + )); } if suggestions.len() == 1 { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 07878defa8c..da0934b67c5 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -602,53 +602,24 @@ impl<T> Trait<T> for X { } else { return false; }; + let Some(def_id) = def_id.as_local() else { + return false; + }; // First look in the `where` clause, as this might be // `fn foo<T>(x: T) where T: Trait`. - for predicate in hir_generics.where_clause.predicates { - if let hir::WherePredicate::BoundPredicate(pred) = predicate { - if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = - pred.bounded_ty.kind - { - if path.res.opt_def_id() == Some(def_id) { - // This predicate is binding type param `A` in `<A as T>::Foo` to - // something, potentially `T`. - } else { - continue; - } - } else { - continue; - } - - if self.constrain_generic_bound_associated_type_structured_suggestion( - diag, - &trait_ref, - pred.bounds, - &assoc, - assoc_substs, - ty, - msg, - false, - ) { - return true; - } - } - } - for param in hir_generics.params { - if self.hir().opt_local_def_id(param.hir_id).map(|id| id.to_def_id()) - == Some(def_id) - { - // This is type param `A` in `<A as T>::Foo`. - return self.constrain_generic_bound_associated_type_structured_suggestion( - diag, - &trait_ref, - param.bounds, - &assoc, - assoc_substs, - ty, - msg, - false, - ); + for pred in hir_generics.bounds_for_param(def_id) { + if self.constrain_generic_bound_associated_type_structured_suggestion( + diag, + &trait_ref, + pred.bounds, + &assoc, + assoc_substs, + ty, + msg, + false, + ) { + return true; } } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index f6d139fe59d..cd4b23fca39 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1120,21 +1120,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { match st[i].abi() { Abi::Scalar(_) => Abi::Scalar(niche_scalar), Abi::ScalarPair(first, second) => { - // We need to use scalar_unit to reset the - // valid range to the maximal one for that - // primitive, because only the niche is - // guaranteed to be initialised, not the - // other primitive. + // Only the niche is guaranteed to be initialised, + // so use union layout for the other primitive. if offset.bytes() == 0 { - Abi::ScalarPair( - niche_scalar, - scalar_unit(second.primitive()), - ) + Abi::ScalarPair(niche_scalar, second.to_union()) } else { - Abi::ScalarPair( - scalar_unit(first.primitive()), - niche_scalar, - ) + Abi::ScalarPair(first.to_union(), niche_scalar) } } _ => Abi::Aggregate { sized: true }, @@ -1329,6 +1320,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } else { // Try to use a ScalarPair for all tagged enums. let mut common_prim = None; + let mut common_prim_initialized_in_all_variants = true; for (field_layouts, layout_variant) in iter::zip(&variants, &layout_variants) { let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else { bug!(); @@ -1336,7 +1328,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst()); let (field, offset) = match (fields.next(), fields.next()) { - (None, None) => continue, + (None, None) => { + common_prim_initialized_in_all_variants = false; + continue; + } (Some(pair), None) => pair, _ => { common_prim = None; @@ -1344,7 +1339,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } }; let prim = match field.abi { - Abi::Scalar(scalar) => scalar.primitive(), + Abi::Scalar(scalar) => { + common_prim_initialized_in_all_variants &= + matches!(scalar, Scalar::Initialized { .. }); + scalar.primitive() + } _ => { common_prim = None; break; @@ -1364,7 +1363,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } } if let Some((prim, offset)) = common_prim { - let pair = self.scalar_pair(tag, scalar_unit(prim)); + let prim_scalar = if common_prim_initialized_in_all_variants { + scalar_unit(prim) + } else { + // Common prim might be uninit. + Scalar::Union { value: prim } + }; + let pair = self.scalar_pair(tag, prim_scalar); let pair_offsets = match pair.fields { FieldsShape::Arbitrary { ref offsets, ref memory_index } => { assert_eq!(memory_index, &[0, 1]); @@ -2587,6 +2592,22 @@ where pointee_info } + + fn is_adt(this: TyAndLayout<'tcx>) -> bool { + matches!(this.ty.kind(), ty::Adt(..)) + } + + fn is_never(this: TyAndLayout<'tcx>) -> bool { + this.ty.kind() == &ty::Never + } + + fn is_tuple(this: TyAndLayout<'tcx>) -> bool { + matches!(this.ty.kind(), ty::Tuple(..)) + } + + fn is_unit(this: TyAndLayout<'tcx>) -> bool { + matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0) + } } impl<'tcx> ty::Instance<'tcx> { diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index adba7d13159..197dc9205b4 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -61,6 +61,10 @@ impl<T> List<T> { static EMPTY_SLICE: InOrder<usize, MaxAlign> = InOrder(0, MaxAlign); unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) } } + + pub fn len(&self) -> usize { + self.len + } } impl<T: Copy> List<T> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d59fdf47904..ec416722c21 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -36,7 +36,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_ID}; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap}; use rustc_hir::Node; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; @@ -131,6 +131,8 @@ pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, pub cstore: Box<CrateStoreDyn>, pub visibilities: FxHashMap<LocalDefId, Visibility>, + /// This field is used to decide whether we should make `PRIVATE_IN_PUBLIC` a hard error. + pub has_pub_restricted: bool, pub access_levels: AccessLevels, pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>, pub maybe_unused_trait_imports: FxHashSet<LocalDefId>, @@ -317,22 +319,6 @@ impl<'tcx> DefIdTree for TyCtxt<'tcx> { } impl Visibility { - pub fn from_hir(visibility: &hir::Visibility<'_>, id: hir::HirId, tcx: TyCtxt<'_>) -> Self { - match visibility.node { - hir::VisibilityKind::Public => Visibility::Public, - hir::VisibilityKind::Crate(_) => Visibility::Restricted(CRATE_DEF_ID.to_def_id()), - hir::VisibilityKind::Restricted { ref path, .. } => match path.res { - // If there is no resolution, `resolve` will have already reported an error, so - // assume that the visibility is public to avoid reporting more privacy errors. - Res::Err => Visibility::Public, - def => Visibility::Restricted(def.def_id()), - }, - hir::VisibilityKind::Inherited => { - Visibility::Restricted(tcx.parent_module(id).to_def_id()) - } - } - } - /// Returns `true` if an item with this visibility is accessible from the given block. pub fn is_accessible_from<T: DefIdTree>(self, module: DefId, tree: T) -> bool { let restriction = match self { diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 7629d7a8259..fb937ded65a 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -3,7 +3,7 @@ use crate::infer::canonical::{self, Canonical}; use crate::lint::LintLevelMap; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; -use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; +use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::AccessLevels; use crate::middle::region; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 5a13216846d..1509de0e930 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2273,7 +2273,7 @@ impl<'tcx> Ty<'tcx> { tcx: TyCtxt<'tcx>, normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>, ) -> (Ty<'tcx>, bool) { - let tail = tcx.struct_tail_with_normalize(self, normalize); + let tail = tcx.struct_tail_with_normalize(self, normalize, || {}); match tail.kind() { // Sized types ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 39038e85b11..918fe49e8e3 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -187,7 +187,7 @@ impl<'tcx> TyCtxt<'tcx> { /// if input `ty` is not a structure at all. pub fn struct_tail_without_normalization(self, ty: Ty<'tcx>) -> Ty<'tcx> { let tcx = self; - tcx.struct_tail_with_normalize(ty, |ty| ty) + tcx.struct_tail_with_normalize(ty, |ty| ty, || {}) } /// Returns the deeply last field of nested structures, or the same type if @@ -203,7 +203,7 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> Ty<'tcx> { let tcx = self; - tcx.struct_tail_with_normalize(ty, |ty| tcx.normalize_erasing_regions(param_env, ty)) + tcx.struct_tail_with_normalize(ty, |ty| tcx.normalize_erasing_regions(param_env, ty), || {}) } /// Returns the deeply last field of nested structures, or the same type if @@ -220,6 +220,10 @@ impl<'tcx> TyCtxt<'tcx> { self, mut ty: Ty<'tcx>, mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>, + // This is currently used to allow us to walk a ValTree + // in lockstep with the type in order to get the ValTree branch that + // corresponds to an unsized field. + mut f: impl FnMut() -> (), ) -> Ty<'tcx> { let recursion_limit = self.recursion_limit(); for iteration in 0.. { @@ -235,12 +239,16 @@ impl<'tcx> TyCtxt<'tcx> { break; } match def.non_enum_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), + Some(field) => { + f(); + ty = field.ty(self, substs); + } None => break, } } ty::Tuple(tys) if let Some((&last_ty, _)) = tys.split_last() => { + f(); ty = last_ty; } |
