Account for UseCloned on expr_use_visitor
This commit is contained in:
parent
edcbc9b535
commit
b43b700250
6 changed files with 98 additions and 2 deletions
|
@ -47,6 +47,21 @@ pub trait Delegate<'tcx> {
|
||||||
/// the id of the binding in the pattern `pat`.
|
/// the id of the binding in the pattern `pat`.
|
||||||
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
|
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
|
||||||
|
|
||||||
|
/// The value found at `place` is used, depending
|
||||||
|
/// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
|
||||||
|
///
|
||||||
|
/// Use of a `Copy` type in a ByUse context is considered a use
|
||||||
|
/// by `ImmBorrow` and `borrow` is called instead. This is because
|
||||||
|
/// a shared borrow is the "minimum access" that would be needed
|
||||||
|
/// to perform a copy.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
|
||||||
|
/// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
|
||||||
|
/// id will be the id of the expression `expr` but the place itself will have
|
||||||
|
/// the id of the binding in the pattern `pat`.
|
||||||
|
fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId);
|
||||||
|
|
||||||
/// The value found at `place` is being borrowed with kind `bk`.
|
/// The value found at `place` is being borrowed with kind `bk`.
|
||||||
/// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
|
/// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
|
||||||
fn borrow(
|
fn borrow(
|
||||||
|
@ -91,6 +106,10 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D {
|
||||||
(**self).consume(place_with_id, diag_expr_id)
|
(**self).consume(place_with_id, diag_expr_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
|
||||||
|
(**self).use_cloned(place_with_id, diag_expr_id)
|
||||||
|
}
|
||||||
|
|
||||||
fn borrow(
|
fn borrow(
|
||||||
&mut self,
|
&mut self,
|
||||||
place_with_id: &PlaceWithHirId<'tcx>,
|
place_with_id: &PlaceWithHirId<'tcx>,
|
||||||
|
@ -143,6 +162,8 @@ pub trait TypeInformationCtxt<'tcx> {
|
||||||
|
|
||||||
fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
|
fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
|
||||||
|
|
||||||
|
fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
|
||||||
|
|
||||||
fn body_owner_def_id(&self) -> LocalDefId;
|
fn body_owner_def_id(&self) -> LocalDefId;
|
||||||
|
|
||||||
fn tcx(&self) -> TyCtxt<'tcx>;
|
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||||
|
@ -184,6 +205,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
|
||||||
self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
|
self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
|
||||||
|
self.infcx.type_is_use_cloned_modulo_regions(self.param_env, ty)
|
||||||
|
}
|
||||||
|
|
||||||
fn body_owner_def_id(&self) -> LocalDefId {
|
fn body_owner_def_id(&self) -> LocalDefId {
|
||||||
self.body_id
|
self.body_id
|
||||||
}
|
}
|
||||||
|
@ -230,6 +255,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
|
||||||
self.0.type_is_copy_modulo_regions(ty)
|
self.0.type_is_copy_modulo_regions(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
|
||||||
|
self.0.type_is_use_cloned_modulo_regions(ty)
|
||||||
|
}
|
||||||
|
|
||||||
fn body_owner_def_id(&self) -> LocalDefId {
|
fn body_owner_def_id(&self) -> LocalDefId {
|
||||||
self.1
|
self.1
|
||||||
}
|
}
|
||||||
|
@ -313,6 +342,23 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
|
||||||
|
debug!("consume_or_clone_expr(expr={:?})", expr);
|
||||||
|
|
||||||
|
let place_with_id = self.cat_expr(expr)?;
|
||||||
|
|
||||||
|
if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
|
||||||
|
self.delegate.borrow_mut().copy(&place_with_id, place_with_id.hir_id);
|
||||||
|
} else if self.cx.type_is_use_cloned_modulo_regions(place_with_id.place.ty()) {
|
||||||
|
self.delegate.borrow_mut().use_cloned(&place_with_id, place_with_id.hir_id);
|
||||||
|
} else {
|
||||||
|
self.delegate.borrow_mut().consume(&place_with_id, place_with_id.hir_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.walk_expr(expr)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
|
fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
|
||||||
let place_with_id = self.cat_expr(expr)?;
|
let place_with_id = self.cat_expr(expr)?;
|
||||||
self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id);
|
self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id);
|
||||||
|
@ -367,7 +413,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Use(expr, _) => {
|
hir::ExprKind::Use(expr, _) => {
|
||||||
self.consume_expr(expr)?;
|
self.consume_or_clone_expr(expr)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::MethodCall(.., receiver, args, _) => {
|
hir::ExprKind::MethodCall(.., receiver, args, _) => {
|
||||||
|
|
|
@ -2045,6 +2045,21 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "debug")]
|
||||||
|
fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
|
||||||
|
let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
|
||||||
|
assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
|
||||||
|
|
||||||
|
self.capture_information.push((
|
||||||
|
place_with_id.place.clone(),
|
||||||
|
ty::CaptureInfo {
|
||||||
|
capture_kind_expr_id: Some(diag_expr_id),
|
||||||
|
path_expr_id: Some(diag_expr_id),
|
||||||
|
capture_kind: ty::UpvarCapture::ByUse,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn borrow(
|
fn borrow(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -683,6 +683,10 @@ impl<'tcx> LateContext<'tcx> {
|
||||||
self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
|
self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
|
||||||
|
self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty)
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the type-checking results for the current body,
|
/// Gets the type-checking results for the current body,
|
||||||
/// or `None` if outside a body.
|
/// or `None` if outside a body.
|
||||||
pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
|
pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
|
||||||
|
|
|
@ -1533,6 +1533,11 @@ rustc_queries! {
|
||||||
query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
|
query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
|
||||||
desc { "computing whether `{}` is `Copy`", env.value }
|
desc { "computing whether `{}` is `Copy`", env.value }
|
||||||
}
|
}
|
||||||
|
/// Trait selection queries. These are best used by invoking `ty.is_use_cloned_modulo_regions()`,
|
||||||
|
/// `ty.is_use_cloned()`, etc, since that will prune the environment where possible.
|
||||||
|
query is_use_cloned_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
|
||||||
|
desc { "computing whether `{}` is `UseCloned`", env.value }
|
||||||
|
}
|
||||||
/// Query backing `Ty::is_sized`.
|
/// Query backing `Ty::is_sized`.
|
||||||
query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
|
query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
|
||||||
desc { "computing whether `{}` is `Sized`", env.value }
|
desc { "computing whether `{}` is `Sized`", env.value }
|
||||||
|
|
|
@ -192,6 +192,18 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
ty.is_trivially_pure_clone_copy() || self.is_copy_raw(typing_env.as_query_input(ty))
|
ty.is_trivially_pure_clone_copy() || self.is_copy_raw(typing_env.as_query_input(ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks whether `ty: UseCloned` holds while ignoring region constraints.
|
||||||
|
///
|
||||||
|
/// This function should not be used if there is an `InferCtxt` available.
|
||||||
|
/// Use `InferCtxt::type_is_copy_modulo_regions` instead.
|
||||||
|
pub fn type_is_use_cloned_modulo_regions(
|
||||||
|
self,
|
||||||
|
typing_env: ty::TypingEnv<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
ty.is_trivially_pure_clone_copy() || self.is_use_cloned_raw(typing_env.as_query_input(ty))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the deeply last field of nested structures, or the same type if
|
/// Returns the deeply last field of nested structures, or the same type if
|
||||||
/// not a structure at all. Corresponds to the only possible unsized field,
|
/// not a structure at all. Corresponds to the only possible unsized field,
|
||||||
/// and its type can be used to determine unsizing strategy.
|
/// and its type can be used to determine unsizing strategy.
|
||||||
|
|
|
@ -10,6 +10,13 @@ fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty
|
||||||
is_item_raw(tcx, query, LangItem::Copy)
|
is_item_raw(tcx, query, LangItem::Copy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_use_cloned_raw<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
|
||||||
|
) -> bool {
|
||||||
|
is_item_raw(tcx, query, LangItem::UseCloned)
|
||||||
|
}
|
||||||
|
|
||||||
fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
|
fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool {
|
||||||
is_item_raw(tcx, query, LangItem::Sized)
|
is_item_raw(tcx, query, LangItem::Sized)
|
||||||
}
|
}
|
||||||
|
@ -33,5 +40,12 @@ fn is_item_raw<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn provide(providers: &mut Providers) {
|
pub(crate) fn provide(providers: &mut Providers) {
|
||||||
*providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers };
|
*providers = Providers {
|
||||||
|
is_copy_raw,
|
||||||
|
is_use_cloned_raw,
|
||||||
|
is_sized_raw,
|
||||||
|
is_freeze_raw,
|
||||||
|
is_unpin_raw,
|
||||||
|
..*providers
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue