diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:11:38 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:12:43 +0000 |
commit | cf94bdc0742c13e2a0cac864c478b8626b266e1b (patch) | |
tree | 044670aa50cc5e2b4229aa0b6b3df6676730c0a6 /compiler/rustc_typeck/src/check/place_op.rs | |
parent | Adding debian version 1.65.0+dfsg1-2. (diff) | |
download | rustc-cf94bdc0742c13e2a0cac864c478b8626b266e1b.tar.xz rustc-cf94bdc0742c13e2a0cac864c478b8626b266e1b.zip |
Merging upstream version 1.66.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_typeck/src/check/place_op.rs')
-rw-r--r-- | compiler/rustc_typeck/src/check/place_op.rs | 451 |
1 files changed, 0 insertions, 451 deletions
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs deleted file mode 100644 index 2e0f37eba..000000000 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ /dev/null @@ -1,451 +0,0 @@ -use crate::check::method::MethodCallee; -use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp}; -use rustc_ast as ast; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::InferOk; -use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast}; -use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, Ty}; -use rustc_span::symbol::{sym, Ident}; -use rustc_span::Span; -use rustc_trait_selection::autoderef::Autoderef; -use std::slice; - -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already. - pub(super) fn lookup_derefing( - &self, - expr: &hir::Expr<'_>, - oprnd_expr: &'tcx hir::Expr<'tcx>, - oprnd_ty: Ty<'tcx>, - ) -> Option<Ty<'tcx>> { - if let Some(mt) = oprnd_ty.builtin_deref(true) { - return Some(mt.ty); - } - - let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?; - let method = self.register_infer_ok_obligations(ok); - if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { - self.apply_adjustments( - oprnd_expr, - vec![Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)), - target: method.sig.inputs()[0], - }], - ); - } else { - span_bug!(expr.span, "input to deref is not a ref?"); - } - let ty = self.make_overloaded_place_return_type(method).ty; - self.write_method_call(expr.hir_id, method); - Some(ty) - } - - /// Type-check `*base_expr[index_expr]` with `base_expr` and `index_expr` type-checked already. - pub(super) fn lookup_indexing( - &self, - expr: &hir::Expr<'_>, - base_expr: &'tcx hir::Expr<'tcx>, - base_ty: Ty<'tcx>, - index_expr: &'tcx hir::Expr<'tcx>, - idx_ty: Ty<'tcx>, - ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - // FIXME(#18741) -- this is almost but not quite the same as the - // autoderef that normal method probing does. They could likely be - // consolidated. - - let mut autoderef = self.autoderef(base_expr.span, base_ty); - let mut result = None; - while result.is_none() && autoderef.next().is_some() { - result = self.try_index_step(expr, base_expr, &autoderef, idx_ty, index_expr); - } - self.register_predicates(autoderef.into_obligations()); - result - } - - fn negative_index( - &self, - ty: Ty<'tcx>, - span: Span, - base_expr: &hir::Expr<'_>, - ) -> Option<(Ty<'tcx>, Ty<'tcx>)> { - let ty = self.resolve_vars_if_possible(ty); - let mut err = self.tcx.sess.struct_span_err( - span, - &format!("negative integers cannot be used to index on a `{ty}`"), - ); - err.span_label(span, &format!("cannot use a negative integer for indexing on `{ty}`")); - if let (hir::ExprKind::Path(..), Ok(snippet)) = - (&base_expr.kind, self.tcx.sess.source_map().span_to_snippet(base_expr.span)) - { - // `foo[-1]` to `foo[foo.len() - 1]` - err.span_suggestion_verbose( - span.shrink_to_lo(), - &format!( - "to access an element starting from the end of the `{ty}`, compute the index", - ), - format!("{snippet}.len() "), - Applicability::MachineApplicable, - ); - } - err.emit(); - Some((self.tcx.ty_error(), self.tcx.ty_error())) - } - - /// To type-check `base_expr[index_expr]`, we progressively autoderef - /// (and otherwise adjust) `base_expr`, looking for a type which either - /// supports builtin indexing or overloaded indexing. - /// This loop implements one step in that search; the autoderef loop - /// is implemented by `lookup_indexing`. - fn try_index_step( - &self, - expr: &hir::Expr<'_>, - base_expr: &hir::Expr<'_>, - autoderef: &Autoderef<'a, 'tcx>, - index_ty: Ty<'tcx>, - index_expr: &hir::Expr<'_>, - ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - let adjusted_ty = - self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); - debug!( - "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ - index_ty={:?})", - expr, base_expr, adjusted_ty, index_ty - ); - - if let hir::ExprKind::Unary( - hir::UnOp::Neg, - hir::Expr { - kind: hir::ExprKind::Lit(hir::Lit { node: ast::LitKind::Int(..), .. }), - .. - }, - ) = index_expr.kind - { - match adjusted_ty.kind() { - ty::Adt(def, _) if self.tcx.is_diagnostic_item(sym::Vec, def.did()) => { - return self.negative_index(adjusted_ty, index_expr.span, base_expr); - } - ty::Slice(_) | ty::Array(_, _) => { - return self.negative_index(adjusted_ty, index_expr.span, base_expr); - } - _ => {} - } - } - - for unsize in [false, true] { - let mut self_ty = adjusted_ty; - if unsize { - // We only unsize arrays here. - if let ty::Array(element_ty, _) = adjusted_ty.kind() { - self_ty = self.tcx.mk_slice(*element_ty); - } else { - continue; - } - } - - // If some lookup succeeds, write callee into table and extract index/element - // type from the method signature. - // If some lookup succeeded, install method in table - let input_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::AutoDeref, - span: base_expr.span, - }); - let method = - self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index); - - if let Some(result) = method { - debug!("try_index_step: success, using overloaded indexing"); - let method = self.register_infer_ok_obligations(result); - - let mut adjustments = self.adjust_steps(autoderef); - if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { - adjustments.push(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)), - target: self.tcx.mk_ref( - *region, - ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty }, - ), - }); - } else { - span_bug!(expr.span, "input to index is not a ref?"); - } - if unsize { - adjustments.push(Adjustment { - kind: Adjust::Pointer(PointerCast::Unsize), - target: method.sig.inputs()[0], - }); - } - self.apply_adjustments(base_expr, adjustments); - - self.write_method_call(expr.hir_id, method); - - return Some((input_ty, self.make_overloaded_place_return_type(method).ty)); - } - } - - None - } - - /// Try to resolve an overloaded place op. We only deal with the immutable - /// variant here (Deref/Index). In some contexts we would need the mutable - /// variant (DerefMut/IndexMut); those would be later converted by - /// `convert_place_derefs_to_mutable`. - pub(super) fn try_overloaded_place_op( - &self, - span: Span, - base_ty: Ty<'tcx>, - arg_tys: &[Ty<'tcx>], - op: PlaceOp, - ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { - debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op); - - let (imm_tr, imm_op) = match op { - PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref), - PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index), - }; - - // If the lang item was declared incorrectly, stop here so that we don't - // run into an ICE (#83893). The error is reported where the lang item is - // declared. - if !has_expected_num_generic_args( - self.tcx, - imm_tr, - match op { - PlaceOp::Deref => 0, - PlaceOp::Index => 1, - }, - ) { - return None; - } - - imm_tr.and_then(|trait_did| { - self.lookup_method_in_trait( - span, - Ident::with_dummy_span(imm_op), - trait_did, - base_ty, - Some(arg_tys), - ) - }) - } - - fn try_mutable_overloaded_place_op( - &self, - span: Span, - base_ty: Ty<'tcx>, - arg_tys: &[Ty<'tcx>], - op: PlaceOp, - ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { - debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op); - - let (mut_tr, mut_op) = match op { - PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut), - PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut), - }; - - // If the lang item was declared incorrectly, stop here so that we don't - // run into an ICE (#83893). The error is reported where the lang item is - // declared. - if !has_expected_num_generic_args( - self.tcx, - mut_tr, - match op { - PlaceOp::Deref => 0, - PlaceOp::Index => 1, - }, - ) { - return None; - } - - mut_tr.and_then(|trait_did| { - self.lookup_method_in_trait( - span, - Ident::with_dummy_span(mut_op), - trait_did, - base_ty, - Some(arg_tys), - ) - }) - } - - /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index` - /// into `DerefMut` and `IndexMut` respectively. - /// - /// This is a second pass of typechecking derefs/indices. We need this because we do not - /// always know whether a place needs to be mutable or not in the first pass. - /// This happens whether there is an implicit mutable reborrow, e.g. when the type - /// is used as the receiver of a method call. - pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) { - // Gather up expressions we want to munge. - let mut exprs = vec![expr]; - - while let hir::ExprKind::Field(ref expr, _) - | hir::ExprKind::Index(ref expr, _) - | hir::ExprKind::Unary(hir::UnOp::Deref, ref expr) = exprs.last().unwrap().kind - { - exprs.push(expr); - } - - debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs); - - // Fix up autoderefs and derefs. - let mut inside_union = false; - for (i, &expr) in exprs.iter().rev().enumerate() { - debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr); - - let mut source = self.node_ty(expr.hir_id); - if matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::Deref, _)) { - // Clear previous flag; after a pointer indirection it does not apply any more. - inside_union = false; - } - if source.is_union() { - inside_union = true; - } - // Fix up the autoderefs. Autorefs can only occur immediately preceding - // overloaded place ops, and will be fixed by them in order to get - // the correct region. - // Do not mutate adjustments in place, but rather take them, - // and replace them after mutating them, to avoid having the - // typeck results borrowed during (`deref_mut`) method resolution. - let previous_adjustments = - self.typeck_results.borrow_mut().adjustments_mut().remove(expr.hir_id); - if let Some(mut adjustments) = previous_adjustments { - for adjustment in &mut adjustments { - if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind - && let Some(ok) = self.try_mutable_overloaded_place_op( - expr.span, - source, - &[], - PlaceOp::Deref, - ) - { - let method = self.register_infer_ok_obligations(ok); - if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { - *deref = OverloadedDeref { region, mutbl, span: deref.span }; - } - // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514). - // This helps avoid accidental drops. - if inside_union - && source.ty_adt_def().map_or(false, |adt| adt.is_manually_drop()) - { - let mut err = self.tcx.sess.struct_span_err( - expr.span, - "not automatically applying `DerefMut` on `ManuallyDrop` union field", - ); - err.help( - "writing to this reference calls the destructor for the old value", - ); - err.help("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor"); - err.emit(); - } - } - source = adjustment.target; - } - self.typeck_results.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments); - } - - match expr.kind { - hir::ExprKind::Index(base_expr, ..) => { - self.convert_place_op_to_mutable(PlaceOp::Index, expr, base_expr); - } - hir::ExprKind::Unary(hir::UnOp::Deref, base_expr) => { - self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr); - } - _ => {} - } - } - } - - fn convert_place_op_to_mutable( - &self, - op: PlaceOp, - expr: &hir::Expr<'_>, - base_expr: &hir::Expr<'_>, - ) { - debug!("convert_place_op_to_mutable({:?}, {:?}, {:?})", op, expr, base_expr); - if !self.typeck_results.borrow().is_method_call(expr) { - debug!("convert_place_op_to_mutable - builtin, nothing to do"); - return; - } - - // Need to deref because overloaded place ops take self by-reference. - let base_ty = self - .typeck_results - .borrow() - .expr_ty_adjusted(base_expr) - .builtin_deref(false) - .expect("place op takes something that is not a ref") - .ty; - - let arg_ty = match op { - PlaceOp::Deref => None, - PlaceOp::Index => { - // We would need to recover the `T` used when we resolve `<_ as Index<T>>::index` - // in try_index_step. This is the subst at index 1. - // - // Note: we should *not* use `expr_ty` of index_expr here because autoderef - // during coercions can cause type of index_expr to differ from `T` (#72002). - // We also could not use `expr_ty_adjusted` of index_expr because reborrowing - // during coercions can also cause type of index_expr to differ from `T`, - // which can potentially cause regionck failure (#74933). - Some(self.typeck_results.borrow().node_substs(expr.hir_id).type_at(1)) - } - }; - let arg_tys = match arg_ty { - None => &[], - Some(ref ty) => slice::from_ref(ty), - }; - - let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op); - let method = match method { - Some(ok) => self.register_infer_ok_obligations(ok), - // Couldn't find the mutable variant of the place op, keep the - // current, immutable version. - None => return, - }; - debug!("convert_place_op_to_mutable: method={:?}", method); - self.write_method_call(expr.hir_id, method); - - let ty::Ref(region, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() else { - span_bug!(expr.span, "input to mutable place op is not a mut ref?"); - }; - - // Convert the autoref in the base expr to mutable with the correct - // region and mutability. - let base_expr_ty = self.node_ty(base_expr.hir_id); - if let Some(adjustments) = - self.typeck_results.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id) - { - let mut source = base_expr_ty; - for adjustment in &mut adjustments[..] { - if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind { - debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment); - let mutbl = AutoBorrowMutability::Mut { - // Deref/indexing can be desugared to a method call, - // so maybe we could use two-phase here. - // See the documentation of AllowTwoPhase for why that's - // not the case today. - allow_two_phase_borrow: AllowTwoPhase::No, - }; - adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)); - adjustment.target = self - .tcx - .mk_ref(*region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() }); - } - source = adjustment.target; - } - - // If we have an autoref followed by unsizing at the end, fix the unsize target. - if let [ - .., - Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, - Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }, - ] = adjustments[..] - { - *target = method.sig.inputs()[0]; - } - } - } -} |