@@ -806,81 +806,80 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> {
806
806
proj : ProjectionElem < VnIndex , Ty < ' tcx > > ,
807
807
) -> Option < ( PlaceTy < ' tcx > , VnIndex ) > {
808
808
let projection_ty = place_ty. projection_ty ( self . tcx , proj) ;
809
- let proj = match proj {
810
- ProjectionElem :: Deref => {
811
- if let Some ( Mutability :: Not ) = place_ty. ty . ref_mutability ( )
809
+ let proj = proj. try_map ( Some , |_| ( ) ) ?;
810
+
811
+ if let ProjectionElem :: Deref = proj
812
+ && !(
813
+ // An immutable borrow `_x` always points to the same value for the
814
+ // lifetime of the borrow, so we can merge all instances of `*_x`.
815
+ place_ty. ty . ref_mutability ( ) == Some ( Mutability :: Not )
812
816
&& projection_ty. ty . is_freeze ( self . tcx , self . typing_env ( ) )
813
- {
814
- if let Value :: Address { base, projection, .. } = self . get ( value)
815
- && let Some ( value) = self . dereference_address ( base, projection)
816
- {
817
- return Some ( ( projection_ty, value) ) ;
818
- }
817
+ )
818
+ {
819
+ return None ;
820
+ }
819
821
820
- // An immutable borrow `_x` always points to the same value for the
821
- // lifetime of the borrow, so we can merge all instances of `*_x`.
822
- return Some ( ( projection_ty, self . insert_deref ( projection_ty. ty , value) ) ) ;
823
- } else {
824
- return None ;
825
- }
822
+ match ( proj, self . get ( value) ) {
823
+ ( ProjectionElem :: Deref , Value :: Address { base, projection, .. } )
824
+ if let Some ( deref) = self . dereference_address ( base, projection) =>
825
+ {
826
+ return Some ( ( projection_ty, deref) ) ;
826
827
}
827
- ProjectionElem :: Downcast ( name, index) => ProjectionElem :: Downcast ( name, index) ,
828
- ProjectionElem :: Field ( f, _) => match self . get ( value) {
829
- Value :: Aggregate ( _, fields) => return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ,
830
- Value :: Union ( active, field) if active == f => return Some ( ( projection_ty, field) ) ,
831
- Value :: Projection ( outer_value, ProjectionElem :: Downcast ( _, read_variant) )
832
- if let Value :: Aggregate ( written_variant, fields) = self . get ( outer_value)
833
- // This pass is not aware of control-flow, so we do not know whether the
834
- // replacement we are doing is actually reachable. We could be in any arm of
835
- // ```
836
- // match Some(x) {
837
- // Some(y) => /* stuff */,
838
- // None => /* other */,
839
- // }
840
- // ```
841
- //
842
- // In surface rust, the current statement would be unreachable.
843
- //
844
- // However, from the reference chapter on enums and RFC 2195,
845
- // accessing the wrong variant is not UB if the enum has repr.
846
- // So it's not impossible for a series of MIR opts to generate
847
- // a downcast to an inactive variant.
848
- && written_variant == read_variant =>
849
- {
850
- return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ;
851
- }
852
- _ => ProjectionElem :: Field ( f, ( ) ) ,
853
- } ,
854
- ProjectionElem :: Index ( idx) => {
855
- if let Value :: Repeat ( inner, _) = self . get ( value) {
856
- return Some ( ( projection_ty, inner) ) ;
857
- }
858
- ProjectionElem :: Index ( idx)
828
+ ( ProjectionElem :: Deref , _) => {
829
+ return Some ( ( projection_ty, self . insert_deref ( projection_ty. ty , value) ) ) ;
859
830
}
860
- ProjectionElem :: ConstantIndex { offset, min_length, from_end } => {
861
- match self . get ( value) {
862
- Value :: Repeat ( inner, _) => {
863
- return Some ( ( projection_ty, inner) ) ;
864
- }
865
- Value :: Aggregate ( _, operands) => {
866
- let offset = if from_end {
867
- operands. len ( ) - offset as usize
868
- } else {
869
- offset as usize
870
- } ;
871
- let value = operands. get ( offset) . copied ( ) ?;
872
- return Some ( ( projection_ty, value) ) ;
873
- }
874
- _ => { }
875
- } ;
876
- ProjectionElem :: ConstantIndex { offset, min_length, from_end }
831
+ ( ProjectionElem :: Field ( f, _) , Value :: Aggregate ( _, fields) ) => {
832
+ return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ;
877
833
}
878
- ProjectionElem :: Subslice { from , to , from_end } => {
879
- ProjectionElem :: Subslice { from , to , from_end }
834
+ ( ProjectionElem :: Field ( f , _ ) , Value :: Union ( active , field ) ) if active == f => {
835
+ return Some ( ( projection_ty , field ) ) ;
880
836
}
881
- ProjectionElem :: OpaqueCast ( _) => ProjectionElem :: OpaqueCast ( ( ) ) ,
882
- ProjectionElem :: UnwrapUnsafeBinder ( _) => ProjectionElem :: UnwrapUnsafeBinder ( ( ) ) ,
883
- } ;
837
+ (
838
+ ProjectionElem :: Field ( f, _) ,
839
+ Value :: Projection ( outer_value, ProjectionElem :: Downcast ( _, read_variant) ) ,
840
+ ) if let Value :: Aggregate ( written_variant, fields) = self . get ( outer_value)
841
+ // This pass is not aware of control-flow, so we do not know whether the
842
+ // replacement we are doing is actually reachable. We could be in any arm of
843
+ // ```
844
+ // match Some(x) {
845
+ // Some(y) => /* stuff */,
846
+ // None => /* other */,
847
+ // }
848
+ // ```
849
+ //
850
+ // In surface rust, the current statement would be unreachable.
851
+ //
852
+ // However, from the reference chapter on enums and RFC 2195,
853
+ // accessing the wrong variant is not UB if the enum has repr.
854
+ // So it's not impossible for a series of MIR opts to generate
855
+ // a downcast to an inactive variant.
856
+ && written_variant == read_variant =>
857
+ {
858
+ return Some ( ( projection_ty, fields[ f. as_usize ( ) ] ) ) ;
859
+ }
860
+ ( ProjectionElem :: Index ( _) , Value :: Repeat ( inner, _) ) => {
861
+ return Some ( ( projection_ty, inner) ) ;
862
+ }
863
+ ( ProjectionElem :: ConstantIndex { .. } , Value :: Repeat ( inner, _) ) => {
864
+ return Some ( ( projection_ty, inner) ) ;
865
+ }
866
+ (
867
+ ProjectionElem :: ConstantIndex { offset, from_end : false , .. } ,
868
+ Value :: Aggregate ( _, operands) ,
869
+ ) => {
870
+ let value = operands. get ( offset as usize ) . copied ( ) ?;
871
+ return Some ( ( projection_ty, value) ) ;
872
+ }
873
+ (
874
+ ProjectionElem :: ConstantIndex { offset, from_end : true , .. } ,
875
+ Value :: Aggregate ( _, operands) ,
876
+ ) => {
877
+ let offset = operands. len ( ) . checked_sub ( offset as usize ) ?;
878
+ let value = operands[ offset] ;
879
+ return Some ( ( projection_ty, value) ) ;
880
+ }
881
+ _ => { }
882
+ }
884
883
885
884
let value = self . insert ( projection_ty. ty , Value :: Projection ( value, proj) ) ;
886
885
Some ( ( projection_ty, value) )
0 commit comments