From 849b0920b1704cae318e8e8709269d2b1c5d0f05 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Feb 2025 21:19:44 +1100 Subject: [PATCH 1/4] Partly flatten the user-type loop in `TypeVerifier::visit_local_decl` --- compiler/rustc_borrowck/src/type_check/mod.rs | 63 ++++++++++--------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 84759a0ae04ab..1f3a15df80cf6 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -456,38 +456,41 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { self.super_local_decl(local, local_decl); - if let Some(user_ty) = &local_decl.user_ty { - for (user_ty, span) in user_ty.projections_and_spans() { - let ty = if !local_decl.is_nonref_binding() { - // If we have a binding of the form `let ref x: T = ..` - // then remove the outermost reference so we can check the - // type annotation for the remaining type. - if let ty::Ref(_, rty, _) = local_decl.ty.kind() { - *rty - } else { - bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); - } + for (user_ty, span) in local_decl + .user_ty + .as_deref() + .into_iter() + .flat_map(UserTypeProjections::projections_and_spans) + { + let ty = if !local_decl.is_nonref_binding() { + // If we have a binding of the form `let ref x: T = ..` + // then remove the outermost reference so we can check the + // type annotation for the remaining type. + if let ty::Ref(_, rty, _) = local_decl.ty.kind() { + *rty } else { - local_decl.ty - }; - - if let Err(terr) = self.typeck.relate_type_and_user_type( - ty, - ty::Invariant, - user_ty, - Locations::All(*span), - ConstraintCategory::TypeAnnotation(AnnotationSource::Declaration), - ) { - span_mirbug!( - self, - local, - "bad user type on variable {:?}: {:?} != {:?} ({:?})", - local, - local_decl.ty, - local_decl.user_ty, - terr, - ); + bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); } + } else { + local_decl.ty + }; + + if let Err(terr) = self.typeck.relate_type_and_user_type( + ty, + ty::Invariant, + user_ty, + Locations::All(*span), + ConstraintCategory::TypeAnnotation(AnnotationSource::Declaration), + ) { + span_mirbug!( + self, + local, + "bad user type on variable {:?}: {:?} != {:?} ({:?})", + local, + local_decl.ty, + local_decl.user_ty, + terr, + ); } } } From bf3bb5fd37b5dcf54a723c8559bba6718630095b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Feb 2025 21:22:36 +1100 Subject: [PATCH 2/4] Flatten the check for ref/non-ref bindings --- compiler/rustc_borrowck/src/type_check/mod.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 1f3a15df80cf6..21b0a62fe4302 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -462,17 +462,15 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { .into_iter() .flat_map(UserTypeProjections::projections_and_spans) { - let ty = if !local_decl.is_nonref_binding() { + let ty = if local_decl.is_nonref_binding() { + local_decl.ty + } else if let &ty::Ref(_, rty, _) = local_decl.ty.kind() { // If we have a binding of the form `let ref x: T = ..` // then remove the outermost reference so we can check the // type annotation for the remaining type. - if let ty::Ref(_, rty, _) = local_decl.ty.kind() { - *rty - } else { - bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); - } + rty } else { - local_decl.ty + bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); }; if let Err(terr) = self.typeck.relate_type_and_user_type( From a64efc72d0811732bbbe9b6d8b678bdebd1848a2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Feb 2025 21:49:33 +1100 Subject: [PATCH 3/4] Avoid a useless clone of `UserTypeProjection` --- compiler/rustc_middle/src/mir/mod.rs | 4 ++-- compiler/rustc_mir_build/src/builder/matches/mod.rs | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ff493fa65a6ab..d74a917f33cc1 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1516,8 +1516,8 @@ impl<'tcx> UserTypeProjections { self.contents.iter().map(|&(ref user_type, _span)| user_type) } - pub fn push_projection(mut self, user_ty: &UserTypeProjection, span: Span) -> Self { - self.contents.push((user_ty.clone(), span)); + pub fn push_user_type(mut self, base_user_ty: UserTypeAnnotationIndex, span: Span) -> Self { + self.contents.push((UserTypeProjection { base: base_user_ty, projs: vec![] }, span)); self } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index ed577f7adeb3d..f551f0ceedafc 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -926,12 +926,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Note that the variance doesn't apply here, as we are tracking the effect // of `user_ty` on any bindings contained with subpattern. - let projection = UserTypeProjection { - base: self.canonical_user_type_annotations.push(annotation.clone()), - projs: Vec::new(), - }; + let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone()); let subpattern_user_ty = - pattern_user_ty.push_projection(&projection, annotation.span); + pattern_user_ty.push_user_type(base_user_ty, annotation.span); self.visit_primary_bindings(subpattern, subpattern_user_ty, f) } From 8bb574fdd301dbb6ff18bd2500ccf463ce8a19d4 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Feb 2025 21:10:04 +1100 Subject: [PATCH 4/4] Don't store a redundant span in user-type projections This span is already present in the corresponding `CanonicalUserTypeAnnotation`, and can be retrieved via the annotation's ID. --- compiler/rustc_borrowck/src/type_check/mod.rs | 11 +++++----- compiler/rustc_middle/src/mir/mod.rs | 21 ++++++------------- compiler/rustc_middle/src/mir/visit.rs | 2 +- .../src/builder/matches/mod.rs | 3 +-- 4 files changed, 13 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 21b0a62fe4302..bd0d98028ae88 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -456,12 +456,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { self.super_local_decl(local, local_decl); - for (user_ty, span) in local_decl - .user_ty - .as_deref() - .into_iter() - .flat_map(UserTypeProjections::projections_and_spans) + for user_ty in + local_decl.user_ty.as_deref().into_iter().flat_map(UserTypeProjections::projections) { + let span = self.typeck.user_type_annotations[user_ty.base].span; + let ty = if local_decl.is_nonref_binding() { local_decl.ty } else if let &ty::Ref(_, rty, _) = local_decl.ty.kind() { @@ -477,7 +476,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { ty, ty::Invariant, user_ty, - Locations::All(*span), + Locations::All(span), ConstraintCategory::TypeAnnotation(AnnotationSource::Declaration), ) { span_mirbug!( diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d74a917f33cc1..71fed4b3e1e9c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1494,7 +1494,7 @@ pub struct SourceScopeLocalData { /// &'static str`. #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct UserTypeProjections { - pub contents: Vec<(UserTypeProjection, Span)>, + pub contents: Vec, } impl<'tcx> UserTypeProjections { @@ -1506,26 +1506,17 @@ impl<'tcx> UserTypeProjections { self.contents.is_empty() } - pub fn projections_and_spans( - &self, - ) -> impl Iterator + ExactSizeIterator { - self.contents.iter() - } - pub fn projections(&self) -> impl Iterator + ExactSizeIterator { - self.contents.iter().map(|&(ref user_type, _span)| user_type) + self.contents.iter() } - pub fn push_user_type(mut self, base_user_ty: UserTypeAnnotationIndex, span: Span) -> Self { - self.contents.push((UserTypeProjection { base: base_user_ty, projs: vec![] }, span)); + pub fn push_user_type(mut self, base_user_type: UserTypeAnnotationIndex) -> Self { + self.contents.push(UserTypeProjection { base: base_user_type, projs: vec![] }); self } - fn map_projections( - mut self, - mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection, - ) -> Self { - self.contents = self.contents.into_iter().map(|(proj, span)| (f(proj), span)).collect(); + fn map_projections(mut self, f: impl FnMut(UserTypeProjection) -> UserTypeProjection) -> Self { + self.contents = self.contents.into_iter().map(f).collect(); self } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 193806f238b1d..98e8f269c57b7 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -857,7 +857,7 @@ macro_rules! make_mir_visitor { source_info: *source_info, }); if let Some(user_ty) = user_ty { - for (user_ty, _) in & $($mutability)? user_ty.contents { + for user_ty in & $($mutability)? user_ty.contents { self.visit_user_type_projection(user_ty); } } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index f551f0ceedafc..6334612eced30 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -927,8 +927,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // of `user_ty` on any bindings contained with subpattern. let base_user_ty = self.canonical_user_type_annotations.push(annotation.clone()); - let subpattern_user_ty = - pattern_user_ty.push_user_type(base_user_ty, annotation.span); + let subpattern_user_ty = pattern_user_ty.push_user_type(base_user_ty); self.visit_primary_bindings(subpattern, subpattern_user_ty, f) }