Skip to content

[perf] Fast path for coercions of TY == TY #142973

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

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -781,8 +781,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
} else {
LaterUseKind::FakeLetRead
}
} else if self.was_captured_by_trait_object(borrow) {
LaterUseKind::TraitCapture
} else if let Some(unsize_span) = self.was_captured_by_trait_object(borrow) {
// We drilled down the span to the actual location of the unsize, rather
// than the location of the borrow.
return (LaterUseKind::TraitCapture, unsize_span, None);
} else if location.statement_index == block.statements.len() {
if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } =
&block.terminator().kind
Expand Down Expand Up @@ -819,7 +821,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
/// Checks if a borrowed value was captured by a trait object. We do this by
/// looking forward in the MIR from the reserve location and checking if we see
/// an unsized cast to a trait object on our data.
fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool {
fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> Option<Span> {
// Start at the reserve location, find the place that we want to see cast to a trait object.
let location = borrow.reserve_location;
let block = &self.body[location.block];
Expand All @@ -835,10 +837,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
if let Some(local) = place.as_local() {
local
} else {
return false;
return None;
}
} else {
return false;
return None;
};

debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue);
Expand Down Expand Up @@ -885,7 +887,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
if from == target {
debug!("was_captured_by_trait_object: ty={:?}", ty);
// Check the type for a trait object.
return match ty.kind() {
let matches = match ty.kind() {
// `&dyn Trait`
ty::Ref(_, ty, _) if ty.is_trait() => true,
// `Box<dyn Trait>`
Expand All @@ -898,11 +900,16 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
// Anything else.
_ => false,
};
if matches {
return Some(stmt.source_info.span);
} else {
return None;
}
}
}
return false;
return None;
}
_ => return false,
_ => return None,
}
}
_ => {}
Expand All @@ -926,7 +933,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
);
// Check if one of the arguments to this function is the target place.
let found_target = args.iter().any(|arg| {
if let Operand::Move(place) = arg.node {
if let Operand::Move(place) | Operand::Copy(place) = arg.node {
if let Some(potential) = place.as_local() {
potential == target
} else {
Expand All @@ -950,6 +957,6 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
}

// We didn't find anything and ran out of locations to check.
false
None
}
}
24 changes: 24 additions & 0 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
return self.coerce_from_inference_variable(a, b);
}

// No coercion needed; types are identical. The only exception is when we have
// a mutable reference, which needs a pair of reborrow adjustments inserted.
if a == b {
if let ty::Ref(_, pointee, ty::Mutability::Mut) = *a.kind() {
return Ok(InferOk {
value: (
vec![
Adjustment { kind: Adjust::Deref(None), target: pointee },
Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut {
allow_two_phase_borrow: AllowTwoPhase::No,
})),
target: a,
},
],
a,
),
obligations: Default::default(),
});
} else {
return Ok(InferOk { value: (vec![], a), obligations: Default::default() });
}
}

// Consider coercing the subtype to a DST
//
// NOTE: this is wrapped in a `commit_if_ok` because it creates
Expand Down
1 change: 0 additions & 1 deletion tests/ui/span/regions-close-over-type-parameter-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ LL | let tmp0 = 3;
LL | let tmp1 = &tmp0;
| ^^^^^ borrowed value does not live long enough
LL | repeater3(tmp1)
| --------------- borrow later captured here by trait object
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This suggestion is was never valid. repeater3 is what's responsible for doing the unsizing, and the fact that we were reporting this as capturing A just because it has the signature fn<'a, A: 'a>(A) -> Box<dyn Tr + 'a> is kinda... coincidental.

LL | };
| - `tmp0` dropped here while still borrowed

Expand Down
Loading