Skip to content
Open
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
26 changes: 19 additions & 7 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ use rustc_middle::ty::adjustment::{
PointerCoercion,
};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Unnormalized};
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, Unnormalized};
use rustc_span::{BytePos, DUMMY_SP, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor};
Expand Down Expand Up @@ -950,16 +950,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
Ok(coerce)
}

/// Get the AdtDefs for the reborrowing if they're reborrowable
fn reborrow_def(
&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
) -> RelateResult<'tcx, (AdtDef<'tcx>, AdtDef<'tcx>)> {
let (ty::Adt(a_def, _), ty::Adt(b_def, b_args)) = (*a.kind(), *b.kind()) else {
return Err(TypeError::Mismatch);
};
match b_args.get(0).map(|r| r.kind()) {
Some(ty::GenericArgKind::Lifetime(_)) => Ok((a_def, b_def)),
_ => Err(TypeError::Mismatch),
}
}

/// Applies generic exclusive reborrowing on type implementing `Reborrow`.
#[instrument(skip(self), level = "trace")]
fn coerce_reborrow(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
debug_assert!(self.shallow_resolve(a) == a);
debug_assert!(self.shallow_resolve(b) == b);

// We need to make sure the two types are compatible for reborrow.
let (ty::Adt(a_def, _), ty::Adt(b_def, _)) = (a.kind(), b.kind()) else {
return Err(TypeError::Mismatch);
};
let (a_def, b_def) = self.reborrow_def(a, b)?;

if a_def.did() == b_def.did() {
// Reborrow is applicable here
self.unify_and(
Expand All @@ -982,9 +996,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
debug_assert!(self.shallow_resolve(b) == b);

// We need to make sure the two types are compatible for reborrow.
let (ty::Adt(a_def, _), ty::Adt(b_def, _)) = (a.kind(), b.kind()) else {
return Err(TypeError::Mismatch);
};
let (a_def, b_def) = self.reborrow_def(a, b)?;
if a_def.did() == b_def.did() {
// CoerceShared cannot be T -> T.
return Err(TypeError::Mismatch);
Expand Down
14 changes: 14 additions & 0 deletions tests/ui/reborrow/reborrow-no-lifetime-rejected.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//@ check-fail

#![feature(reborrow)]

use std::marker::Reborrow;

struct Thing;
impl<'a> Reborrow for Thing {}
//~^ ERROR implementing `Reborrow` does not allow multiple lifetimes or fields to be coerced
fn foo(_: Thing) {}
fn main() {
let x = Thing;
foo(x);
}
8 changes: 8 additions & 0 deletions tests/ui/reborrow/reborrow-no-lifetime-rejected.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: implementing `Reborrow` does not allow multiple lifetimes or fields to be coerced
--> $DIR/reborrow-no-lifetime-rejected.rs:8:1
|
LL | impl<'a> Reborrow for Thing {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

Loading