-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extend two-phase borrows to apply to method receiver autorefs #49348
Changes from all commits
d37a7ab
96ae0ee
d64bd2a
d8352af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -662,9 +662,13 @@ trait ToBorrowKind { fn to_borrow_kind(&self) -> BorrowKind; } | |
|
||
impl ToBorrowKind for AutoBorrowMutability { | ||
fn to_borrow_kind(&self) -> BorrowKind { | ||
use rustc::ty::adjustment::AllowTwoPhase; | ||
match *self { | ||
AutoBorrowMutability::Mutable { allow_two_phase_borrow } => | ||
BorrowKind::Mut { allow_two_phase_borrow }, | ||
BorrowKind::Mut { allow_two_phase_borrow: match allow_two_phase_borrow { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we should propagate the |
||
AllowTwoPhase::Yes => true, | ||
AllowTwoPhase::No => false | ||
}}, | ||
AutoBorrowMutability::Immutable => | ||
BorrowKind::Shared, | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,7 +67,7 @@ use rustc::hir::def_id::DefId; | |
use rustc::infer::{Coercion, InferResult, InferOk}; | ||
use rustc::infer::type_variable::TypeVariableOrigin; | ||
use rustc::traits::{self, ObligationCause, ObligationCauseCode}; | ||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; | ||
use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; | ||
use rustc::ty::{self, TypeAndMut, Ty, ClosureSubsts}; | ||
use rustc::ty::fold::TypeFoldable; | ||
use rustc::ty::error::TypeError; | ||
|
@@ -84,6 +84,13 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { | |
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, | ||
cause: ObligationCause<'tcx>, | ||
use_lub: bool, | ||
/// Determines whether or not allow_two_phase_borrow is set on any | ||
/// autoref adjustments we create while coercing. We don't want to | ||
/// allow deref coercions to create two-phase borrows, at least initially, | ||
/// but we do need two-phase borrows for function argument reborrows. | ||
/// See #47489 and #48598 | ||
/// See docs on the "AllowTwoPhase" type for a more detailed discussion | ||
allow_two_phase: AllowTwoPhase, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, lovin' the comments |
||
} | ||
|
||
impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { | ||
|
@@ -123,10 +130,13 @@ fn success<'tcx>(adj: Vec<Adjustment<'tcx>>, | |
} | ||
|
||
impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { | ||
fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self { | ||
fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: these days, I tend to move over to rustfmt style when changing a sig anyway
|
||
cause: ObligationCause<'tcx>, | ||
allow_two_phase: AllowTwoPhase) -> Self { | ||
Coerce { | ||
fcx, | ||
cause, | ||
allow_two_phase, | ||
use_lub: false, | ||
} | ||
} | ||
|
@@ -424,10 +434,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { | |
let mutbl = match mt_b.mutbl { | ||
hir::MutImmutable => AutoBorrowMutability::Immutable, | ||
hir::MutMutable => AutoBorrowMutability::Mutable { | ||
// Deref-coercion is a case where we deliberately | ||
// disallow two-phase borrows in its initial | ||
// deployment; see discussion on PR #47489. | ||
allow_two_phase_borrow: false, | ||
allow_two_phase_borrow: self.allow_two_phase, | ||
} | ||
}; | ||
adjustments.push(Adjustment { | ||
|
@@ -473,7 +480,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { | |
let mutbl = match mt_b.mutbl { | ||
hir::MutImmutable => AutoBorrowMutability::Immutable, | ||
hir::MutMutable => AutoBorrowMutability::Mutable { | ||
allow_two_phase_borrow: false, | ||
// We don't allow two-phase borrows here, at least for initial | ||
// implementation. If it happens that this coercion is a function argument, | ||
// the reborrow in coerce_borrowed_ptr will pick it up. | ||
allow_two_phase_borrow: AllowTwoPhase::No, | ||
} | ||
}; | ||
Some((Adjustment { | ||
|
@@ -751,13 +761,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { | |
pub fn try_coerce(&self, | ||
expr: &hir::Expr, | ||
expr_ty: Ty<'tcx>, | ||
target: Ty<'tcx>) | ||
target: Ty<'tcx>, | ||
allow_two_phase: AllowTwoPhase) | ||
-> RelateResult<'tcx, Ty<'tcx>> { | ||
let source = self.resolve_type_vars_with_obligations(expr_ty); | ||
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); | ||
|
||
let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); | ||
let coerce = Coerce::new(self, cause); | ||
let coerce = Coerce::new(self, cause, allow_two_phase); | ||
let ok = self.commit_if_ok(|_| coerce.coerce(source, target))?; | ||
|
||
let (adjustments, _) = self.register_infer_ok_obligations(ok); | ||
|
@@ -771,7 +782,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { | |
debug!("coercion::can({:?} -> {:?})", source, target); | ||
|
||
let cause = self.cause(syntax_pos::DUMMY_SP, ObligationCauseCode::ExprAssignable); | ||
let coerce = Coerce::new(self, cause); | ||
// We don't ever need two-phase here since we throw out the result of the coercion | ||
let coerce = Coerce::new(self, cause, AllowTwoPhase::No); | ||
self.probe(|_| coerce.coerce(source, target)).is_ok() | ||
} | ||
|
||
|
@@ -840,7 +852,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { | |
return Ok(fn_ptr); | ||
} | ||
|
||
let mut coerce = Coerce::new(self, cause.clone()); | ||
// Configure a Coerce instance to compute the LUB. | ||
// We don't allow two-phase borrows on any autorefs this creates since we | ||
// probably aren't processing function arguments here and even if we were, | ||
// they're going to get autorefed again anyway and we can apply 2-phase borrows | ||
// at that time. | ||
let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No); | ||
coerce.use_lub = true; | ||
|
||
// First try to coerce the new expression to the type of the previous ones, | ||
|
@@ -1106,7 +1123,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> | |
if self.pushed == 0 { | ||
// Special-case the first expression we are coercing. | ||
// To be honest, I'm not entirely sure why we do this. | ||
fcx.try_coerce(expression, expression_ty, self.expected_ty) | ||
// We don't allow two-phase borrows, see comment in try_find_coercion_lub for why | ||
fcx.try_coerce(expression, expression_ty, self.expected_ty, AllowTwoPhase::No) | ||
} else { | ||
match self.expressions { | ||
Expressions::Dynamic(ref exprs) => | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -97,7 +97,7 @@ use rustc::mir::interpret::{GlobalId}; | |
use rustc::ty::subst::{Kind, Subst, Substs}; | ||
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode}; | ||
use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate}; | ||
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; | ||
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; | ||
use rustc::ty::fold::TypeFoldable; | ||
use rustc::ty::maps::Providers; | ||
use rustc::ty::util::{Representability, IntTypeExt, Discr}; | ||
|
@@ -2341,12 +2341,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { | |
let mutbl = match mt.mutbl { | ||
hir::MutImmutable => AutoBorrowMutability::Immutable, | ||
hir::MutMutable => AutoBorrowMutability::Mutable { | ||
// FIXME (#46747): arguably indexing is | ||
// "just another kind of call"; perhaps it | ||
// would be more consistent to allow | ||
// two-phase borrows for .index() | ||
// receivers here. | ||
allow_two_phase_borrow: false, | ||
// 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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are you just referring to our general desire for caution? (I didn't see any specific notes about indexing) |
||
allow_two_phase_borrow: AllowTwoPhase::No, | ||
} | ||
}; | ||
adjustments.push(Adjustment { | ||
|
@@ -2649,7 +2648,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { | |
// to, which is `expected_ty` if `rvalue_hint` returns an | ||
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. | ||
let coerce_ty = expected.and_then(|e| e.only_has_type(self)); | ||
self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty)); | ||
// We're processing function arguments so we definitely want to use | ||
// two-phase borrows. | ||
self.demand_coerce(&arg, | ||
checked_ty, | ||
coerce_ty.unwrap_or(formal_ty), | ||
AllowTwoPhase::Yes); | ||
|
||
// 3. Relate the expected type and the formal one, | ||
// if the expected type was used for the coercion. | ||
|
@@ -2812,7 +2816,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { | |
expr, | ||
ExpectHasType(expected), | ||
needs); | ||
self.demand_coerce(expr, ty, expected) | ||
// checks don't need two phase | ||
self.demand_coerce(expr, ty, expected, AllowTwoPhase::No) | ||
} | ||
|
||
fn check_expr_with_hint(&self, expr: &'gcx hir::Expr, | ||
|
@@ -3645,7 +3650,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { | |
// (It shouldn't actually matter for unary ops whether | ||
// we enable two-phase borrows or not, since a unary | ||
// op has no additional operands.) | ||
allow_two_phase_borrow: false, | ||
allow_two_phase_borrow: AllowTwoPhase::No, | ||
} | ||
}; | ||
self.apply_adjustments(oprnd, vec![Adjustment { | ||
|
@@ -4112,7 +4117,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { | |
let base_t = self.structurally_resolved_type(expr.span, base_t); | ||
match self.lookup_indexing(expr, base, base_t, idx_t, needs) { | ||
Some((index_ty, element_ty)) => { | ||
self.demand_coerce(idx, idx_t, index_ty); | ||
// two-phase not needed because index_ty is never mutable | ||
self.demand_coerce(idx, idx_t, index_ty, AllowTwoPhase::No); | ||
element_ty | ||
} | ||
None => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lovin' the comments <3