Skip to content

Support field-wise CoerceShared reborrows#157101

Closed
P8L1 wants to merge 3 commits into
rust-lang:mainfrom
P8L1:fix-reborrow-coerceshared-field-relations
Closed

Support field-wise CoerceShared reborrows#157101
P8L1 wants to merge 3 commits into
rust-lang:mainfrom
P8L1:fix-reborrow-coerceshared-field-relations

Conversation

@P8L1
Copy link
Copy Markdown
Contributor

@P8L1 P8L1 commented May 29, 2026

View all comments

This PR extends generic shared reborrows so that CoerceShared validates and lowers source-to-target structs field by field, rather than relying on a same-layout, transmute-like copy.

The core change is a shared rustc_middle::ty::reborrow helper that computes the field correspondence used by CoerceShared validation, borrow checking, const-eval, and codegen.

The correspondence rules are:

  • Named structs match non-PhantomData data fields by name.
  • Tuple structs match non-PhantomData data fields by position.
  • PhantomData fields are ignored.
  • Every target data field must correspond to a source data field.

CoerceShared impl validation now checks each corresponding field relation. A field relation is accepted when the field is:

  • Copy-compatible,
  • recursively CoerceShared-compatible, or
  • a mutable-reference-to-shared-reference reborrow.

The validation also rejects mismatched field styles, missing source fields, mismatched reborrow lifetimes, and inaccessible fields with targeted diagnostics.

Borrowck now adds shared generic reborrow constraints recursively through the validated field relations, while still issuing the loan for the original source place as a whole. This ensures source-only fields remain protected for the inferred target lifetime when the target omits fields from the source.

Const-eval and codegen now lower shared generic reborrows recursively into the target fields instead of treating the operation as a transmute-like copy. This covers nested CoerceShared fields and layout-changing source/target pairs.

Fixes

Fixes #156566.
Fixes #156309.
Fixes #156315.

PR scope

I did not split these into smaller PRs because the issues mostly share the same root cause: CoerceShared needed a field-by-field validation and lowering model. So when making this, I just decided to write it in a way that will fix the issues anyway.

Tracking

#145612
https://rust-lang.github.io/rust-project-goals/2025h2/autoreborrow-traits.html

CC. @aapoalas, @dingxiangfei2009
r? @RalfJung

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 29, 2026
@P8L1

This comment was marked as outdated.

@rustbot rustbot added the F-reborrow `#![feature(reborrow)]`; see #145612 label May 29, 2026
@P8L1

This comment was marked as outdated.

@P8L1

This comment was marked as outdated.

@rust-bors

This comment has been minimized.

@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented May 29, 2026

🔨 5 commits were squashed into b8e47e8.

@rust-bors rust-bors Bot force-pushed the fix-reborrow-coerceshared-field-relations branch from 9713677 to b8e47e8 Compare May 29, 2026 09:36
@rust-log-analyzer

This comment has been minimized.

@P8L1 P8L1 force-pushed the fix-reborrow-coerceshared-field-relations branch from b8e47e8 to 83d9f22 Compare May 31, 2026 17:45
@rust-log-analyzer

This comment has been minimized.

@P8L1

This comment was marked as outdated.

@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented Jun 1, 2026

Unclosed quote in argument. Run @bors help to see available commands.

@P8L1
Copy link
Copy Markdown
Contributor Author

P8L1 commented Jun 1, 2026

@bors squash msg="Support field-wise CoerceShared reborrows"

@rust-bors

This comment has been minimized.

@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented Jun 1, 2026

🔨 7 commits were squashed into 8987e4a.

@rust-bors rust-bors Bot force-pushed the fix-reborrow-coerceshared-field-relations branch from 62ec49c to 8987e4a Compare June 1, 2026 06:26
@P8L1 P8L1 marked this pull request as ready for review June 1, 2026 06:28
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 1, 2026

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

This PR changes MIR

cc @oli-obk, @RalfJung, @JakobDegen, @vakaras

The Cranelift subtree was changed

cc @bjorn3

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 1, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 1, 2026

r? @folkertdev

rustbot has assigned @folkertdev.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 73 candidates
  • Random selection from 17 candidates

@rustbot rustbot assigned RalfJung and unassigned folkertdev Jun 1, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 1, 2026

RalfJung is not on the review rotation at the moment.
They may take a while to respond.

@RalfJung
Copy link
Copy Markdown
Member

RalfJung commented Jun 1, 2026

Why are you asking for my review here? I have nothing to do with this feature and don't have capacity to take on a new feature, especially not a massive PR like this.

@rustbot reroll

@P8L1
Copy link
Copy Markdown
Contributor Author

P8L1 commented Jun 1, 2026

Hello @P8L1 and thank you for taking interest in the reborrow work.

With per-field reborrowing the proposed design will break away from a few fundamental but important assumptions and intended use cases of this language feature. A design document would certainly bring @aapoalas and me onto the same page and help us understand why the extension would be desirable. Let us chat on Zulip as well if you need any help.

Thanks, that makes sense.

I wrote up a PR-specific design note here please review it and share your thoughts so this PR can proceed!

Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Borrow-set gathering records MIR Reborrow loans.
This file now treats malformed generic reborrow shapes as delayed compiler bugs instead of hard panics.

View changes since the review

Comment on lines 305 to +330
} else if let &mir::Rvalue::Reborrow(target, mutability, borrowed_place) = rvalue {
let borrowed_place_ty = borrowed_place.ty(self.body, self.tcx).ty;
let &ty::Adt(reborrowed_adt, _reborrowed_args) = borrowed_place_ty.kind() else {
unreachable!()
self.tcx.dcx().span_delayed_bug(
self.body.source_info(location).span,
format!("generic reborrow source is not an ADT: {borrowed_place_ty:?}"),
);
return;
};
let &ty::Adt(target_adt, assigned_args) = target.kind() else {
self.tcx.dcx().span_delayed_bug(
self.body.source_info(location).span,
format!("generic reborrow target is not an ADT: {target:?}"),
);
return;
};
let &ty::Adt(target_adt, assigned_args) = target.kind() else { unreachable!() };
let Some(ty::GenericArgKind::Lifetime(region)) = assigned_args.get(0).map(|r| r.kind())
else {
bug!(
"hir-typeck passed but {} does not have a lifetime argument",
if mutability == Mutability::Mut { "Reborrow" } else { "CoerceShared" }
self.tcx.dcx().span_delayed_bug(
self.body.source_info(location).span,
format!(
"hir-typeck passed but {} does not have a lifetime argument",
if mutability == Mutability::Mut { "Reborrow" } else { "CoerceShared" }
),
);
return;
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

This replaces unreachable!/bug! assumptions with delayed bugs and early returns.
The borrow-set visitor can now avoid constructing a loan from invalid generic reborrow MIR.

View changes since the review

Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Borrowck type checking is where generic reborrow MIR becomes region and type constraints.
The main change is replacing ad hoc one-field CoerceShared handling with recursive field-wise constraints.

View changes since the review

Comment on lines +2493 to +2509
let ty::Adt(_, dest_args) = dest_ty.kind() else {
span_mirbug!(
self,
borrowed_place,
"generic reborrow target is not an ADT: {dest_ty:?}"
);
return;
};
let Some(ty::GenericArgKind::Lifetime(dest_region)) = dest_args.get(0).map(|r| r.kind())
else {
span_mirbug!(
self,
borrowed_place,
"generic reborrow target does not have a lifetime argument: {dest_ty:?}"
);
return;
};
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

This turns shape assumptions on the reborrow target into MIR bugs with early returns.
Borrowck still records liveness for the target lifetime, but only after proving the first generic arg is a lifetime.

View changes since the review

Comment on lines +2527 to +2543
// CoerceShared relates distinct ADTs field-wise. Impl validation guarantees that
// every target field has the corresponding source field and that each field relation
// is Copy-compatible, recursively CoerceShared-compatible, or `&mut T` to `&T`.
// The loan itself is still issued for `borrowed_place` as a whole, so source-only
// fields remain protected for the inferred target lifetime. Under the current
// single-lifetime impl model, that is the source lifetime.
if self
.add_generic_shared_reborrow_constraints(
location,
borrowed_place,
borrowed_ty,
dest_ty,
category,
)
.is_err()
{
return;
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

The previous local name-based loop is replaced by a recursive helper call.
The key invariant is that validation, borrowck, and materialization all consume the same canonical field pairs.

View changes since the review

@theemathas
Copy link
Copy Markdown
Contributor

This PR currently does not correctly handle decl_macro hygiene:

#![feature(reborrow, decl_macro)]

use std::marker::{CoerceShared, Reborrow};

macro my_macro($field:ident) {
    pub struct MyMut<'a> {
        $field: &'a i32,
        field: &'a i64,
    }

    #[derive(Clone, Copy)]
    pub struct MyRef<'a> {
        $field: &'a i32,
        field: &'a i64,
    }

    impl Reborrow for MyMut<'_> {}

    impl<'a> CoerceShared<MyRef<'a>> for MyMut<'a> {}
}

my_macro!(field);
error: implementing `CoerceShared` requires corresponding fields to match, be reborrowable with `CoerceShared`, or coerce a mutable reference field to a shared reference field
  --> src/lib.rs:14:9
   |
 7 |         $field: &'a i32,
   |         --------------- source field `field` has type `&'a i32`
...
14 |         field: &'a i64,
   |         ^^^^^^^^^^^^^^ target field `field` has type `&'a i64`
...
22 | my_macro!(field);
   | ---------------- in this macro invocation
   |
   = note: this error originates in the macro `my_macro` (in Nightly builds, run with -Z macro-backtrace for more info)

Comment on lines 2546 to +2564
// Exclusive reborrow
self.relate_types(
if let Err(terr) = self.relate_types(
borrowed_ty,
ty::Variance::Covariant,
dest_ty,
location.to_locations(),
category,
)
.unwrap();
) {
span_mirbug!(
self,
borrowed_place,
"bad generic exclusive reborrow relation ({:?}: {:?}): {:?}",
borrowed_ty,
dest_ty,
terr
);
}
}
}
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Exclusive reborrows keep the ordinary same-type relation but now report a MIR bug instead of unwrapping.
This is defensive behavior for malformed MIR and does not change the success path.

View changes since the review

}
}

fn add_generic_shared_reborrow_constraints(
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

This helper recursively walks the validated CoerceShared field relation.
It normalizes field types in borrowck's inference context before deciding whether to relate leaves or recurse.

View changes since the review

Comment on lines +2583 to +2616
if let Err(terr) = self.relate_types_structurally_relating_aliases(
borrowed_ty.peel_refs(),
ty::Variance::Covariant,
dest_ty.peel_refs(),
location.to_locations(),
category,
) {
span_mirbug!(
self,
borrowed_place,
"bad generic shared reborrow field relation ({:?}: {:?}): {:?}",
borrowed_ty,
dest_ty,
terr
);
return Err(());
}

self.constraints.outlives_constraints.push(OutlivesConstraint {
sup: ref_region.as_var(),
sub: borrow_region.as_var(),
locations: location.to_locations(),
span: location.to_locations().span(self.body),
category,
variance_info: ty::VarianceDiagInfo::default(),
from_closure: false,
});
return Ok(());
}

match (borrowed_ty.kind(), dest_ty.kind()) {
(ty::Adt(borrowed_adt, borrowed_args), ty::Adt(dest_adt, dest_args))
if borrowed_adt.did() != dest_adt.did() =>
{
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

The &mut T to &T leaf relates pointee types structurally and then emits the target-outlives-source constraint.
This mirrors built-in shared reborrowing while allowing aliases and projections in the pointee type.

View changes since the review

Comment on lines +2617 to +2656
let field_pairs = match reborrow::coerce_shared_field_pairs(
tcx,
*borrowed_adt,
*borrowed_args,
*dest_adt,
*dest_args,
) {
Ok(field_pairs) => field_pairs,
Err(CoerceSharedFieldPairError::FieldStyleMismatch) => {
span_mirbug!(
self,
borrowed_place,
"generic shared reborrow has unsupported field structure: \
{borrowed_ty:?} -> {dest_ty:?}"
);
return Err(());
}
Err(CoerceSharedFieldPairError::MissingSourceField { .. }) => {
span_mirbug!(
self,
borrowed_place,
"generic shared reborrow is missing a source field: \
{borrowed_ty:?} -> {dest_ty:?}"
);
return Err(());
}
};

for field_pair in field_pairs {
self.add_generic_shared_reborrow_constraints(
location,
borrowed_place,
field_pair.source.ty,
field_pair.target.ty,
category,
)?;
}

Ok(())
}
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Distinct ADTs are expanded through canonical CoerceShared field pairs, then each field pair is related recursively.
This is the borrowck side of nested field-wise reborrows such as OuterMut to OuterRef.

View changes since the review

Comment on lines +2657 to +2677
_ => {
if let Err(terr) = self.relate_types_structurally_relating_aliases(
borrowed_ty,
ty::Variance::Covariant,
dest_ty,
location.to_locations(),
category,
) {
span_mirbug!(
self,
borrowed_place,
"bad generic shared reborrow field relation ({:?}: {:?}): {:?}",
borrowed_ty,
dest_ty,
terr
);
Err(())
} else {
Ok(())
}
}
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

The fallback relates non-recursive leaves structurally, including aliases, using the same variance as the old field loop.
This covers copied scalar fields and equal field types after normalization.

View changes since the review

Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

HIR type checking creates the generic reborrow coercion adjustment before MIR borrowck sees it. This file adds a structural shape guard so only field-corresponding CoerceShared impls produce reborrow MIR.

View changes since the review

};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Unnormalized};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Unnormalized, reborrow};
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

HIR typeck imports the shared reborrow helper for a structural shape guard before creating a reborrow adjustment. This keeps obviously malformed CoerceShared shapes out of MIR.

View changes since the review

}

/// Applies generic exclusive reborrowing on type implementing `Reborrow`.
/// Applies generic shared reborrowing on types implementing `CoerceShared`.
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

The method comment is corrected to describe CoerceShared shared reborrowing, matching the code path below. The new shape guard rejects non-structs, missing lifetimes, and missing field correspondence before registering the trait obligation.

View changes since the review

Comment on lines +1008 to +1012
// This is only a shape guard for producing well-formed MIR adjustments. The field-type
// relation remains owned by the `CoerceShared` obligation and builtin impl validation.
if !self.coerce_shared_reborrow_structurally_well_formed(a, b) {
return Err(TypeError::Mismatch);
}
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

This helper checks only ADT struct shape, exactly-one-lifetime presence, and successful canonical field pairing. It does not inspect per-field type compatibility beyond what the pair helper needs for field metadata.

View changes since the review

}
}

fn coerce_shared_reborrow_structurally_well_formed(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

This helper is the HIR typeck shape gate for producing ExprKind::Reborrow adjustments. It accepts only struct ADTs with one lifetime argument each and successful canonical field pairing.

View changes since the review

@P8L1
Copy link
Copy Markdown
Contributor Author

P8L1 commented Jun 2, 2026

This PR currently does not correctly handle decl_macro hygiene:

#![feature(reborrow, decl_macro)]

use std::marker::{CoerceShared, Reborrow};

macro my_macro($field:ident) {
    pub struct MyMut<'a> {
        $field: &'a i32,
        field: &'a i64,
    }

    #[derive(Clone, Copy)]
    pub struct MyRef<'a> {
        $field: &'a i32,
        field: &'a i64,
    }

    impl Reborrow for MyMut<'_> {}

    impl<'a> CoerceShared<MyRef<'a>> for MyMut<'a> {}
}

my_macro!(field);
error: implementing `CoerceShared` requires corresponding fields to match, be reborrowable with `CoerceShared`, or coerce a mutable reference field to a shared reference field
  --> src/lib.rs:14:9
   |
 7 |         $field: &'a i32,
   |         --------------- source field `field` has type `&'a i32`
...
14 |         field: &'a i64,
   |         ^^^^^^^^^^^^^^ target field `field` has type `&'a i64`
...
22 | my_macro!(field);
   | ---------------- in this macro invocation
   |
   = note: this error originates in the macro `my_macro` (in Nightly builds, run with -Z macro-backtrace for more info)

Ok im going to fix this now then finish comments

Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

This new helper module is the canonical home for Reborrow and CoerceShared field metadata: it extracts participating ADT fields, preserves projection indices and spans, filters PhantomData, and computes source-to-target field pairs.

View changes since the review

use crate::ty::{self, Ty, TyCtxt};

#[derive(Clone, Copy, Debug)]
pub struct ReborrowField<'tcx> {
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

This struct is the data contract for one participating field. index preserves the real ADT field index for MIR projection, ident is needed for hygiene-aware named-field matching, name is kept for diagnostics, ty is the instantiated field type, and span lets validation point at the field that caused the problem.

The split between ident and name matters: name is useful for user-facing output, but matching named fields must not be reduced to raw textual-name equality.

View changes since the review

}

#[derive(Clone, Copy, Debug)]
pub struct CoerceSharedFieldPair<'tcx> {
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

CoerceSharedFieldPair is the normalized relation later compiler phases operate on: each target field has a specific source field. The error enum keeps correspondence failures field-local, distinguishing mismatched struct styles from a target field that has no valid source-side data field.

View changes since the review

}

/// Returns the instantiated non-`PhantomData` fields that participate in generic reborrows.
pub fn reborrow_data_fields<'tcx>(
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

This function extracts the instantiated non-PhantomData fields that actually participate in field-wise reborrowing. It deliberately preserves the original FieldIdx, because matching ignores marker fields but MIR / CTFE / codegen still need to project from the real ADT layout.

View changes since the review

Comment on lines +74 to +78
if source_variant.ctor_kind() != target_variant.ctor_kind() {
return Err(CoerceSharedFieldPairError::FieldStyleMismatch);
}

let by_position = matches!(target_variant.ctor_kind(), Some(CtorKind::Fn));
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

This is the boundary between named-field and tuple-field correspondence. CoerceShared does not allow named structs and tuple structs to be matched against each other, because the meaning of “corresponding field” is different in the two styles.

View changes since the review

let target_fields = reborrow_data_fields(tcx, target_def, target_args);

if by_position {
target_fields
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Tuple structs match by filtered data-field ordinal, not by original field index. This lets PhantomData be ignored for correspondence while still preserving each field’s original FieldIdx inside the returned pair for later projection.

View changes since the review

if by_position {
target_fields
.into_iter()
.zip(source_fields.into_iter().map(Some).chain(std::iter::repeat(None)))
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

The repeat(None) tail makes the target-driven failure mode explicit: every target data field must have a corresponding source data field. Extra source fields do not matter for constructing the shared target view, but missing source fields are rejected.

View changes since the review

Comment on lines +99 to +101
.find(|source| {
tcx.hygienic_eq(target.ident, source.ident, source_variant.def_id)
})
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

This is the hygiene-sensitive part of named-field correspondence. Two fields can print with the same textual name under decl_macro while still being distinct identifiers, so this must use rustc’s hygienic field identity rather than raw Symbol equality. (The decl macro hygiene bug was caused by me just comparing names)

View changes since the review

tcx.hygienic_eq(target.ident, source.ident, source_variant.def_id)
})
.ok_or(CoerceSharedFieldPairError::MissingSourceField { target })?;

Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

The named-field branch is target-driven: each non-PhantomData target field must resolve to a hygienically corresponding source field. If no source field matches, the helper reports the target field as missing instead of silently omitting it or falling back to position.

View changes since the review

@theemathas

This comment was marked as resolved.

@theemathas

This comment was marked as resolved.

@P8L1
Copy link
Copy Markdown
Contributor Author

P8L1 commented Jun 2, 2026

Ok I would like to start off by saying sorry for all the pings.
I have fixed the decl macro hygiene issues.

I have recently received valid criticism about the reviewability of this PR. Thus, I took my self-review notes, summarised them and posted them as review comments here. This was done to make it easier for reviewers to wrap their heads around the changes.

I have also updated the Design Note to reflect the new decl_macro hygiene changes

@P8L1
Copy link
Copy Markdown
Contributor Author

P8L1 commented Jun 2, 2026

The CoerceShared impl check does not resolve associated types before checking whether the field types match. Is this intentional?

#![feature(reborrow)]

use std::marker::{CoerceShared, Reborrow};

trait Trait {
    type Assoc;
}
impl Trait for i32 {
    type Assoc = i64;
}

struct MyMut<'a> {
    x: &'a (),
    y: i64,
}

#[derive(Copy, Clone)]
struct MyRef<'a> {
    x: &'a (),
    y: <i32 as Trait>::Assoc,
}

impl Reborrow for MyMut<'_> {}

impl<'a> CoerceShared<MyRef<'a>> for MyMut<'a> {}
error: implementing `CoerceShared` requires corresponding fields to match, be reborrowable with `CoerceShared`, or coerce a mutable reference field to a shared reference field
  --> src/lib.rs:20:5
   |
14 |     y: i64,
   |     ------ source field `y` has type `i64`
...
20 |     y: <i32 as Trait>::Assoc,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^ target field `y` has type `<i32 as Trait>::Assoc`

The CoerceShared impl check does not verify that lifetimes match. Is this intentional?

// Compiles without errors

#![feature(reborrow)]

use std::marker::{CoerceShared, Reborrow};

struct MyMut<'a> {
    x: &'static (),
    y: &'a (),
}

#[derive(Copy, Clone)]
struct MyRef<'a> {
    x: &'a (),
    y: &'static (),
}

impl Reborrow for MyMut<'_> {}

impl<'a> CoerceShared<MyRef<'a>> for MyMut<'a> {}

Thanks, both of these were bugs in the impl validation rather than intentional behavior.

I pushed a fix in Validate CoerceShared field relations after normalization. CoerceShared field validation now structurally normalizes the field types before accepting equality or the built-in &mut T -> &T field relation, evaluates the generated obligations, and resolves region constraints before returning success.

That fixes the associated-type case because <i32 as Trait>::Assoc is normalized before the field equality check. It also rejects the swapped-lifetime case because field-internal lifetime constraints are now actually resolved instead of relying only on the top-level reborrow lifetime argument.

@P8L1
Copy link
Copy Markdown
Contributor Author

P8L1 commented Jun 2, 2026

Once again, I updated the design note to reflect the new "Validate CoerceShared field relations after normalization" changes

if !errors.is_empty() { Err(errors) } else { Ok(()) }
}

pub(crate) fn coerce_shared_info<'tcx>(
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Validates a builtin CoerceShared impl. Source and target shapes that later reborrow phases cannot interpret are rejected here. Field-type legality is delegated to canonical field-pair validation below.

View changes since the review


// FIXME(#155345): This should return `Unnormalized`
fn collect_struct_data_fields<'tcx>(
fn validate_reborrow_field_access(
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Rejects fields that later reborrow lowering cannot legally project. Field-wise validation must be able to name every participating field, so private, otherwise inaccessible, and non-exhaustive fields are rejected before canonical field-pair validation.

View changes since the review

Ok(())
}

fn validate_coerce_shared_fields<'tcx>(
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Builds and validates canonical CoerceShared source-to-target field pairs. Pair construction defines the correspondence used by validation and later phases: named fields use hygienic identity, while tuple fields use the ordinal among non-PhantomData data fields.

View changes since the review

Ok(())
}

fn validate_coerce_shared_field<'tcx>(
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Validates one corresponding CoerceShared field relation. The accepted cases are deliberately narrow: a builtin &mut T to &T shared-reference leaf, a copy-compatible equal field type, or a recursive SourceField: CoerceShared<TargetField> obligation. Successful paths must discharge generated obligations and region constraints before accepting.

View changes since the review

ocx.resolve_regions_and_report_errors(impl_did, param_env, [])
}

enum FieldRelation {
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Field relation to prove after normalization in the impl-validation context. This keeps equality separate from the builtin shared-reference leaf. The MutRefToSharedRef case is not type equality: it normalizes both fields, strips exactly one &mut/& layer, and records the required lifetime constraint before relating the referents.

View changes since the review

}

enum FieldRelation {
Equal,
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Require normalized source and target field types to be equal.

View changes since the review


enum FieldRelation {
Equal,
MutRefToSharedRef,
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Require &mut T to relate to &T after adding the lifetime constraint.

View changes since the review

MutRefToSharedRef,
}

fn field_tys_satisfy_relation_after_normalization_and_resolution<'tcx>(
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Normalizes, relates, and resolves a field-type relation as a single check. Alias and projection types are structurally normalized in the impl-validation context. Generated obligations are evaluated with ambiguity as failure, the normalized types are structurally related, and region constraints must resolve before this returns true.

View changes since the review

&& ocx.resolve_regions(impl_did, param_env, []).is_empty()
}

fn assert_field_type_is_copy<'tcx>(
Copy link
Copy Markdown
Contributor Author

@P8L1 P8L1 Jun 2, 2026

Choose a reason for hiding this comment

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

Verifies the copy-compatible leaf case after field equality is established. The equal-type field path may only accept a leaf when that field type is Copy, and the generated copy obligations and regions must also resolve.

View changes since the review

@theemathas
Copy link
Copy Markdown
Contributor

theemathas commented Jun 4, 2026

The following code causes an ICE with this PR:

#![feature(reborrow)]

use std::marker::{CoerceShared, Reborrow};

pub trait Trait {
    type Assoc;
}
impl<T> Trait for T {
    type Assoc = T;
}

#[expect(dead_code)]
pub struct MyMut<'a, T>(&'a (), T);

#[expect(dead_code)]
#[derive(Copy, Clone)]
struct MyRef<'a, T>(&'a (), <T as Trait>::Assoc);

impl<T: Copy> Reborrow for MyMut<'_, T> {}

impl<'a, T: Copy> CoerceShared<MyRef<'a, T>> for MyMut<'a, T> {}

pub fn foo<T: Trait + Copy>(x: MyMut<'_, T>) {
    let _: MyRef<'_, T> = x;
}
Error output
note: no errors encountered even though delayed bugs were created

note: those delayed bugs will now be shown as internal compiler errors

error: internal compiler error: broken MIR in DefId(0:22 ~ foo[9561]::foo) (_1): bad generic shared reborrow field relation (T/#0: Alias(AliasTy { args: [T/#0], kind: Projection { def_id: DefId(0:7 ~ foo[9561]::Trait::Assoc) }, .. })): NoSolution
  --> src/lib.rs:24:27
   |
24 |     let _: MyRef<'_, T> = x;
   |                           ^
   |
note: delayed at compiler/rustc_borrowck/src/type_check/mod.rs:2665:21
         0: std::backtrace_rs::backtrace::libunwind::trace
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/../../backtrace/src/backtrace/libunwind.rs:117:9
         1: std::backtrace_rs::backtrace::trace_unsynchronized::<<std::backtrace::Backtrace>::create::{closure#0}>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/../../backtrace/src/backtrace/mod.rs:66:14
         2: <std::backtrace::Backtrace>::create
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/backtrace.rs:331:13
         3: emit_diagnostic
                   at /Users/timch/rust/compiler/rustc_errors/src/lib.rs:1242:41
         4: emit_diagnostic
                   at /Users/timch/rust/compiler/rustc_errors/src/lib.rs:837:33
         5: emit_producing_error_guaranteed<rustc_span::ErrorGuaranteed>
                   at /Users/timch/rust/compiler/rustc_errors/src/diagnostic.rs:1275:29
         6: span_delayed_bug<rustc_span::span_encoding::Span, alloc::string::String>
                   at /Users/timch/rust/compiler/rustc_errors/src/lib.rs:1057:82
         7: mirbug
                   at /Users/timch/rust/compiler/rustc_borrowck/src/type_check/mod.rs:221:15
         8: add_generic_shared_reborrow_constraints
                   at /Users/timch/rust/compiler/rustc_borrowck/src/type_check/mod.rs:56:9
         9: add_generic_shared_reborrow_constraints
                   at /Users/timch/rust/compiler/rustc_borrowck/src/type_check/mod.rs:2646:26
        10: add_generic_reborrow_constraint
                   at /Users/timch/rust/compiler/rustc_borrowck/src/type_check/mod.rs:2534:18
        11: visit_rvalue
                   at /Users/timch/rust/compiler/rustc_borrowck/src/type_check/mod.rs:1615:22
        12: visit_statement
                   at /Users/timch/rust/compiler/rustc_borrowck/src/type_check/mod.rs:611:14
        13: visit_body
                   at /Users/timch/rust/compiler/rustc_borrowck/src/type_check/mod.rs:600:22
        14: type_check
                   at /Users/timch/rust/compiler/rustc_borrowck/src/type_check/mod.rs:169:12
        15: borrowck_collect_region_constraints
                   at /Users/timch/rust/compiler/rustc_borrowck/src/lib.rs:360:9
        16: do_mir_borrowck
                   at /Users/timch/rust/compiler/rustc_borrowck/src/root_cx.rs:269:26
        17: mir_borrowck
                   at /Users/timch/rust/compiler/rustc_borrowck/src/lib.rs:141:17
        18: __rust_begin_short_backtrace
                   at /Users/timch/rust/compiler/rustc_query_impl/src/query_impl.rs:118:46
        19: {closure#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:472:16
        20: {closure#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:56:9
        21: try_with<core::cell::Cell<*const ()>, rustc_middle::ty::context::tls::enter_context::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/local.rs:462:12
        22: with<core::cell::Cell<*const ()>, rustc_middle::ty::context::tls::enter_context::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/local.rs:426:20
        23: enter_context<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:53:9
        24: {closure#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/dep_graph/mod.rs:67:9
        25: {closure#0}<rustc_middle::dep_graph::with_deps::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:86:36
        26: with_context_opt<rustc_middle::ty::context::tls::with_context::{closure_env#0}<rustc_middle::dep_graph::with_deps::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:75:18
        27: with_context<rustc_middle::dep_graph::with_deps::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:86:5
        28: with_deps<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/dep_graph/mod.rs:65:5
        29: with_task<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, rustc_middle::query::erase::ErasedData<[u8; 8]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/dep_graph/graph.rs:350:14
        30: {closure#1}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:469:24
        31: {closure#0}<rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, (rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:56:9
        32: try_with<core::cell::Cell<*const ()>, rustc_middle::ty::context::tls::enter_context::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, (rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex)>, (rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/local.rs:462:12
        33: with<core::cell::Cell<*const ()>, rustc_middle::ty::context::tls::enter_context::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, (rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex)>, (rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/local.rs:426:20
        34: enter_context<rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>, (rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:53:9
        35: {closure#0}<(rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex), rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/plumbing.rs:74:9
        36: {closure#0}<rustc_query_impl::plumbing::start_query::{closure_env#0}<(rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex), rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>>, (rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:86:36
        37: with_context_opt<rustc_middle::ty::context::tls::with_context::{closure_env#0}<rustc_query_impl::plumbing::start_query::{closure_env#0}<(rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex), rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>>, (rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex)>, (rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:75:18
        38: with_context<rustc_query_impl::plumbing::start_query::{closure_env#0}<(rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex), rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>>, (rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:86:5
        39: start_query<(rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex), rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/plumbing.rs:61:5
        40: execute_job_incr<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:467:36
        41: try_execute_query<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>, true>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:323:17
        42: {closure#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:646:9
        43: maybe_grow<(rustc_middle::query::erase::ErasedData<[u8; 8]>, core::option::Option<rustc_middle::dep_graph::graph::DepNodeIndex>), rustc_query_impl::execution::execute_query_incr_inner::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>>
                   at /Users/timch/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/stacker-0.1.21/src/lib.rs:57:9
        44: ensure_sufficient_stack<(rustc_middle::query::erase::ErasedData<[u8; 8]>, core::option::Option<rustc_middle::dep_graph::graph::DepNodeIndex>), rustc_query_impl::execution::execute_query_incr_inner::{closure_env#0}<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>>
                   at /Users/timch/rust/compiler/rustc_data_structures/src/stack.rs:21:5
        45: execute_query_incr_inner<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:645:36
        46: __rust_end_short_backtrace
                   at /Users/timch/rust/compiler/rustc_query_impl/src/query_impl.rs:61:25
        47: query_ensure_ok_or_done<rustc_data_structures::vec_cache::VecCache<rustc_span::def_id::LocalDefId, rustc_middle::query::erase::ErasedData<[u8; 8]>, rustc_middle::dep_graph::graph::DepNodeIndex>>
                   at /Users/timch/rust/compiler/rustc_middle/src/query/inner.rs:63:13
        48: mir_borrowck<rustc_span::def_id::LocalDefId>
                   at /Users/timch/rust/compiler/rustc_middle/src/query/plumbing.rs:589:21
        49: {closure#0}
                   at /Users/timch/rust/compiler/rustc_interface/src/passes.rs:1165:33
        50: {closure#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>
                   at /Users/timch/rust/compiler/rustc_middle/src/hir/map.rs:371:79
        51: {closure#0}<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], rustc_middle::hir::map::{impl#3}::par_hir_body_owners::{closure_env#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>>
                   at /Users/timch/rust/compiler/rustc_data_structures/src/sync/parallel.rs:182:30
        52: call_once<(), rustc_data_structures::sync::parallel::par_for_each_in::{closure#0}::{closure#1}::{closure_env#0}<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], rustc_middle::hir::map::{impl#3}::par_hir_body_owners::{closure_env#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/core/src/panic/unwind_safe.rs:275:9
        53: do_call<core::panic::unwind_safe::AssertUnwindSafe<rustc_data_structures::sync::parallel::par_for_each_in::{closure#0}::{closure#1}::{closure_env#0}<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], rustc_middle::hir::map::{impl#3}::par_hir_body_owners::{closure_env#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>>>, ()>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:581:40
        54: catch_unwind<(), core::panic::unwind_safe::AssertUnwindSafe<rustc_data_structures::sync::parallel::par_for_each_in::{closure#0}::{closure#1}::{closure_env#0}<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], rustc_middle::hir::map::{impl#3}::par_hir_body_owners::{closure_env#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>>>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:544:19
        55: catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<rustc_data_structures::sync::parallel::par_for_each_in::{closure#0}::{closure#1}::{closure_env#0}<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], rustc_middle::hir::map::{impl#3}::par_hir_body_owners::{closure_env#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>>>, ()>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panic.rs:359:14
        56: run<(), rustc_data_structures::sync::parallel::par_for_each_in::{closure#0}::{closure#1}::{closure_env#0}<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], rustc_middle::hir::map::{impl#3}::par_hir_body_owners::{closure_env#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>>>
                   at /Users/timch/rust/compiler/rustc_data_structures/src/sync/parallel.rs:23:9
        57: {closure#1}<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], rustc_middle::hir::map::{impl#3}::par_hir_body_owners::{closure_env#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>>
                   at /Users/timch/rust/compiler/rustc_data_structures/src/sync/parallel.rs:182:23
        58: for_each<rustc_span::def_id::LocalDefId, rustc_data_structures::sync::parallel::par_for_each_in::{closure#0}::{closure_env#1}<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], rustc_middle::hir::map::{impl#3}::par_hir_body_owners::{closure_env#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/core/src/slice/iter/macros.rs:301:21
        59: {closure#0}<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], rustc_middle::hir::map::{impl#3}::par_hir_body_owners::{closure_env#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>>
                   at /Users/timch/rust/compiler/rustc_data_structures/src/sync/parallel.rs:181:27
        60: parallel_guard<(), rustc_data_structures::sync::parallel::par_for_each_in::{closure_env#0}<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], rustc_middle::hir::map::{impl#3}::par_hir_body_owners::{closure_env#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>>>
                   at /Users/timch/rust/compiler/rustc_data_structures/src/sync/parallel.rs:39:15
        61: par_for_each_in<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], rustc_middle::hir::map::{impl#3}::par_hir_body_owners::{closure_env#0}<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>>
                   at /Users/timch/rust/compiler/rustc_data_structures/src/sync/parallel.rs:176:5
        62: par_hir_body_owners<rustc_interface::passes::run_required_analyses::{closure#2}::{closure_env#0}>
                   at /Users/timch/rust/compiler/rustc_middle/src/hir/map.rs:371:9
        63: {closure#2}
                   at /Users/timch/rust/compiler/rustc_interface/src/passes.rs:1155:13
        64: run<(), rustc_interface::passes::run_required_analyses::{closure_env#2}>
                   at /Users/timch/rust/compiler/rustc_data_structures/src/profiling.rs:845:9
        65: time<(), rustc_interface::passes::run_required_analyses::{closure_env#2}>
                   at /Users/timch/rust/compiler/rustc_session/src/utils.rs:17:50
        66: run_required_analyses
                   at /Users/timch/rust/compiler/rustc_interface/src/passes.rs:1154:10
        67: analysis
                   at /Users/timch/rust/compiler/rustc_interface/src/passes.rs:1198:5
        68: __rust_begin_short_backtrace
                   at /Users/timch/rust/compiler/rustc_query_impl/src/query_impl.rs:118:46
        69: {closure#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:472:16
        70: {closure#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:56:9
        71: try_with<core::cell::Cell<*const ()>, rustc_middle::ty::context::tls::enter_context::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/local.rs:462:12
        72: with<core::cell::Cell<*const ()>, rustc_middle::ty::context::tls::enter_context::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/local.rs:426:20
        73: enter_context<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:53:9
        74: {closure#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/dep_graph/mod.rs:67:9
        75: {closure#0}<rustc_middle::dep_graph::with_deps::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:86:36
        76: with_context_opt<rustc_middle::ty::context::tls::with_context::{closure_env#0}<rustc_middle::dep_graph::with_deps::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:75:18
        77: with_context<rustc_middle::dep_graph::with_deps::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:86:5
        78: with_deps<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/dep_graph/mod.rs:65:5
        79: with_task<rustc_query_impl::execution::execute_job_incr::{closure#1}::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, rustc_middle::query::erase::ErasedData<[u8; 0]>>
                   at /Users/timch/rust/compiler/rustc_middle/src/dep_graph/graph.rs:343:14
        80: {closure#1}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:469:24
        81: {closure#0}<rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, (rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:56:9
        82: try_with<core::cell::Cell<*const ()>, rustc_middle::ty::context::tls::enter_context::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, (rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex)>, (rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/local.rs:462:12
        83: with<core::cell::Cell<*const ()>, rustc_middle::ty::context::tls::enter_context::{closure_env#0}<rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, (rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex)>, (rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/local.rs:426:20
        84: enter_context<rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>, (rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:53:9
        85: {closure#0}<(rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex), rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/plumbing.rs:74:9
        86: {closure#0}<rustc_query_impl::plumbing::start_query::{closure_env#0}<(rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex), rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>>, (rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:86:36
        87: with_context_opt<rustc_middle::ty::context::tls::with_context::{closure_env#0}<rustc_query_impl::plumbing::start_query::{closure_env#0}<(rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex), rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>>, (rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex)>, (rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:75:18
        88: with_context<rustc_query_impl::plumbing::start_query::{closure_env#0}<(rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex), rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>>, (rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex)>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:86:5
        89: start_query<(rustc_middle::query::erase::ErasedData<[u8; 0]>, rustc_middle::dep_graph::graph::DepNodeIndex), rustc_query_impl::execution::execute_job_incr::{closure_env#1}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/plumbing.rs:61:5
        90: execute_job_incr<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:467:36
        91: try_execute_query<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>, true>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:323:17
        92: {closure#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:646:9
        93: maybe_grow<(rustc_middle::query::erase::ErasedData<[u8; 0]>, core::option::Option<rustc_middle::dep_graph::graph::DepNodeIndex>), rustc_query_impl::execution::execute_query_incr_inner::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>>
                   at /Users/timch/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/stacker-0.1.21/src/lib.rs:57:9
        94: ensure_sufficient_stack<(rustc_middle::query::erase::ErasedData<[u8; 0]>, core::option::Option<rustc_middle::dep_graph::graph::DepNodeIndex>), rustc_query_impl::execution::execute_query_incr_inner::{closure_env#0}<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>>
                   at /Users/timch/rust/compiler/rustc_data_structures/src/stack.rs:21:5
        95: execute_query_incr_inner<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>
                   at /Users/timch/rust/compiler/rustc_query_impl/src/execution.rs:645:36
        96: __rust_end_short_backtrace
                   at /Users/timch/rust/compiler/rustc_query_impl/src/query_impl.rs:61:25
        97: query_ensure_ok_or_done<rustc_middle::query::caches::SingleCache<rustc_middle::query::erase::ErasedData<[u8; 0]>>>
                   at /Users/timch/rust/compiler/rustc_middle/src/query/inner.rs:63:13
        98: analysis
                   at /Users/timch/rust/compiler/rustc_middle/src/query/plumbing.rs:589:21
        99: {closure#2}
                   at /Users/timch/rust/compiler/rustc_driver_impl/src/lib.rs:326:29
       100: {closure#0}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>
                   at /Users/timch/rust/compiler/rustc_interface/src/passes.rs:1026:80
       101: call_once<core::option::Option<rustc_interface::queries::Linker>, rustc_interface::passes::create_and_enter_global_ctxt::{closure#2}::{closure_env#0}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/core/src/panic/unwind_safe.rs:275:9
       102: do_call<core::panic::unwind_safe::AssertUnwindSafe<rustc_interface::passes::create_and_enter_global_ctxt::{closure#2}::{closure_env#0}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>>, core::option::Option<rustc_interface::queries::Linker>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:581:40
       103: catch_unwind<core::option::Option<rustc_interface::queries::Linker>, core::panic::unwind_safe::AssertUnwindSafe<rustc_interface::passes::create_and_enter_global_ctxt::{closure#2}::{closure_env#0}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:544:19
       104: catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<rustc_interface::passes::create_and_enter_global_ctxt::{closure#2}::{closure_env#0}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>>, core::option::Option<rustc_interface::queries::Linker>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panic.rs:359:14
       105: {closure#2}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>
                   at /Users/timch/rust/compiler/rustc_interface/src/passes.rs:1026:23
       106: {closure#1}<rustc_interface::passes::create_and_enter_global_ctxt::{closure_env#2}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>, core::option::Option<rustc_interface::queries::Linker>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context.rs:779:37
       107: {closure#0}<rustc_middle::ty::context::{impl#15}::enter::{closure_env#1}<rustc_interface::passes::create_and_enter_global_ctxt::{closure_env#2}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>, core::option::Option<rustc_interface::queries::Linker>>, core::option::Option<rustc_interface::queries::Linker>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:56:9
       108: try_with<core::cell::Cell<*const ()>, rustc_middle::ty::context::tls::enter_context::{closure_env#0}<rustc_middle::ty::context::{impl#15}::enter::{closure_env#1}<rustc_interface::passes::create_and_enter_global_ctxt::{closure_env#2}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>, core::option::Option<rustc_interface::queries::Linker>>, core::option::Option<rustc_interface::queries::Linker>>, core::option::Option<rustc_interface::queries::Linker>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/local.rs:462:12
       109: with<core::cell::Cell<*const ()>, rustc_middle::ty::context::tls::enter_context::{closure_env#0}<rustc_middle::ty::context::{impl#15}::enter::{closure_env#1}<rustc_interface::passes::create_and_enter_global_ctxt::{closure_env#2}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>, core::option::Option<rustc_interface::queries::Linker>>, core::option::Option<rustc_interface::queries::Linker>>, core::option::Option<rustc_interface::queries::Linker>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/local.rs:426:20
       110: enter_context<rustc_middle::ty::context::{impl#15}::enter::{closure_env#1}<rustc_interface::passes::create_and_enter_global_ctxt::{closure_env#2}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>, core::option::Option<rustc_interface::queries::Linker>>, core::option::Option<rustc_interface::queries::Linker>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context/tls.rs:53:9
       111: enter<rustc_interface::passes::create_and_enter_global_ctxt::{closure_env#2}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>, core::option::Option<rustc_interface::queries::Linker>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context.rs:779:9
       112: create_global_ctxt<core::option::Option<rustc_interface::queries::Linker>, rustc_interface::passes::create_and_enter_global_ctxt::{closure_env#2}<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>>
                   at /Users/timch/rust/compiler/rustc_middle/src/ty/context.rs:973:13
       113: create_and_enter_global_ctxt<core::option::Option<rustc_interface::queries::Linker>, rustc_driver_impl::run_compiler::{closure#0}::{closure_env#2}>
                   at /Users/timch/rust/compiler/rustc_interface/src/passes.rs:986:5
       114: {closure#0}
                   at /Users/timch/rust/compiler/rustc_driver_impl/src/lib.rs:299:22
       115: {closure#0}<(), rustc_driver_impl::run_compiler::{closure_env#0}>
                   at /Users/timch/rust/compiler/rustc_interface/src/interface.rs:496:80
       116: call_once<(), rustc_interface::interface::run_compiler::{closure#1}::{closure_env#0}<(), rustc_driver_impl::run_compiler::{closure_env#0}>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/core/src/panic/unwind_safe.rs:275:9
       117: do_call<core::panic::unwind_safe::AssertUnwindSafe<rustc_interface::interface::run_compiler::{closure#1}::{closure_env#0}<(), rustc_driver_impl::run_compiler::{closure_env#0}>>, ()>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:581:40
       118: catch_unwind<(), core::panic::unwind_safe::AssertUnwindSafe<rustc_interface::interface::run_compiler::{closure#1}::{closure_env#0}<(), rustc_driver_impl::run_compiler::{closure_env#0}>>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:544:19
       119: catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<rustc_interface::interface::run_compiler::{closure#1}::{closure_env#0}<(), rustc_driver_impl::run_compiler::{closure_env#0}>>, ()>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panic.rs:359:14
       120: {closure#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>
                   at /Users/timch/rust/compiler/rustc_interface/src/interface.rs:496:23
       121: {closure#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>
                   at /Users/timch/rust/compiler/rustc_interface/src/util.rs:205:17
       122: {closure#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>
                   at /Users/timch/rust/compiler/rustc_interface/src/util.rs:161:24
       123: set<rustc_span::SessionGlobals, rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure#0}::{closure_env#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>, ()>
                   at /Users/timch/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/scoped-tls-1.0.1/src/lib.rs:137:9
       124: create_session_globals_then<(), rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure#0}::{closure_env#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>>
                   at /Users/timch/rust/compiler/rustc_span/src/lib.rs:154:21
       125: {closure#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>
                   at /Users/timch/rust/compiler/rustc_interface/src/util.rs:157:17
       126: __rust_begin_short_backtrace<rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure_env#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>, ()>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/sys/backtrace.rs:166:18
       127: {closure#0}<rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure_env#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>, ()>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/lifecycle.rs:91:13
       128: call_once<(), std::thread::lifecycle::spawn_unchecked::{closure#1}::{closure_env#0}<rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure_env#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>, ()>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/core/src/panic/unwind_safe.rs:275:9
       129: do_call<core::panic::unwind_safe::AssertUnwindSafe<std::thread::lifecycle::spawn_unchecked::{closure#1}::{closure_env#0}<rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure_env#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>, ()>>, ()>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:581:40
       130: catch_unwind<(), core::panic::unwind_safe::AssertUnwindSafe<std::thread::lifecycle::spawn_unchecked::{closure#1}::{closure_env#0}<rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure_env#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>, ()>>>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:544:19
       131: catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<std::thread::lifecycle::spawn_unchecked::{closure#1}::{closure_env#0}<rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure_env#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>, ()>>, ()>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panic.rs:359:14
       132: {closure#1}<rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure_env#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>, ()>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/thread/lifecycle.rs:89:26
       133: call_once<std::thread::lifecycle::spawn_unchecked::{closure_env#1}<rustc_interface::util::run_in_thread_with_globals::{closure#0}::{closure_env#0}<rustc_interface::util::run_in_thread_pool_with_globals::{closure_env#0}<rustc_interface::interface::run_compiler::{closure_env#1}<(), rustc_driver_impl::run_compiler::{closure_env#0}>, ()>, ()>, ()>, ()>
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/core/src/ops/function.rs:250:5
       134: <alloc::boxed::Box<dyn core::ops::function::FnOnce<(), Output = ()> + core::marker::Send> as core::ops::function::FnOnce<()>>::call_once
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/alloc/src/boxed.rs:2249:9
       135: <std::sys::thread::unix::Thread>::new::thread_start
                   at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/sys/thread/unix.rs:118:17
       136: __pthread_cond_wait
      
  --> src/lib.rs:24:27
   |
24 |     let _: MyRef<'_, T> = x;
   |                           ^

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: please make sure that you have updated to the latest nightly

note: please attach the file at `/Users/timch/foo/rustc-ice-2026-06-04T08_33_27-6798.txt` to your bug report

note: rustc 1.98.0-dev running on aarch64-apple-darwin

note: compiler flags: --crate-type lib -C embed-bitcode=no -C debuginfo=2 -C split-debuginfo=unpacked -C incremental=[REDACTED]

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
end of query stack
error: could not compile `foo` (lib)

I think that rust was unable to figure out that T::Assoc = T inside foo, due to using the T: Trait bound instead of the impl<T> Trait for T.

Copy link
Copy Markdown
Contributor

@aapoalas aapoalas left a comment

Choose a reason for hiding this comment

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

Hey, first: thank you for the work you've done.

However, after some discussion with Xiang we've come to the conclusion that unfortunately this direction this PR is walking us is indeed a bit wrong. Here's what we'd want to do:

  1. Perform all well-formedness checking in the coherence/builtin.rs: there shouldn't be any need to perform any checks relating to the correctness of the traits or field types in THIR building, MIR building, or the borrow checker.
  2. Similarly to now, the THIR will emit a single reborrow adjustment that is used in borrow checking.
  3. An MIR pass will be added that lowers the single Rvalue::Reborrow into field-wise actions. This goes into fn run_runtime_lowering_passes.

This gets us "both flavours of reborrowing": simple reborrowing in the MIR for borrow checking, and field-by-field reborrowing in the lowered MIR for code generation. Actual code generation backends shouldn't have to do all that much work for reborrowing to work at this point.

If you want to help, here's how:

  1. The tests you're adding here are good; adding them in a separate PR would be great. It's okay if some or all of them produce ICEs in that PR, there's a tests/ui/crashes folder for that and we can add in a tests/ui/crashes/reborrow folder specifically for those.
  2. The work you've done on the well-formedness check (coherence/builtin.rs) deserves a separate PR. We can then build on top of that to improve the checking to get to the desired state of the well-formedness check containing all the check logic.
  3. A distant third is the MIR pass itself: this we'll be very deeply involved in so collaborating may be harder, but as we get into building the pass I can ping you or send an email and let you know if there is anything in particular you could help with.

On the communication front, I recommend using your own voice and words in the future: you're doing yourself a disfavour by using an LLM to translate and generate text for you. You do not need to communicate in perfect English - it's perfectly okay to communicate at the level that you're capable of, and nothing more or less.

Cheers.

View changes since this review

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 4, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 4, 2026

Reminder, once the PR becomes ready for a review, use @rustbot ready.

Copy link
Copy Markdown
Contributor

@aapoalas aapoalas Jun 4, 2026

Choose a reason for hiding this comment

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

note: Seeing this file change is a sign that this PR puts us on the wrong path: there shouldn't really be any codegen-specific handling of reborrowing, or if there is then it should just be an extra way to generate a copy.

View changes since the review

let ty::Adt(dest_adt, dest_args) = dest_ty.kind() else { bug!() };
let [dest_arg, ..] = ***dest_args else { bug!() };
let ty::GenericArgKind::Lifetime(dest_region) = dest_arg.kind() else { bug!() };
let ty::Adt(_, dest_args) = dest_ty.kind() else {
Copy link
Copy Markdown
Contributor

@aapoalas aapoalas Jun 4, 2026

Choose a reason for hiding this comment

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

note: These changes are questionable. These paths should be unreachable, so why are we adding extra dead code?

View changes since the review

@P8L1
Copy link
Copy Markdown
Contributor Author

P8L1 commented Jun 5, 2026

Hey, first: thank you for the work you've done.

However, after some discussion with Xiang we've come to the conclusion that unfortunately this direction this PR is walking us is indeed a bit wrong. Here's what we'd want to do:

  1. Perform all well-formedness checking in the coherence/builtin.rs: there shouldn't be any need to perform any checks relating to the correctness of the traits or field types in THIR building, MIR building, or the borrow checker.
  2. Similarly to now, the THIR will emit a single reborrow adjustment that is used in borrow checking.
  3. An MIR pass will be added that lowers the single Rvalue::Reborrow into field-wise actions. This goes into fn run_runtime_lowering_passes.

This gets us "both flavours of reborrowing": simple reborrowing in the MIR for borrow checking, and field-by-field reborrowing in the lowered MIR for code generation. Actual code generation backends shouldn't have to do all that much work for reborrowing to work at this point.

If you want to help, here's how:

  1. The tests you're adding here are good; adding them in a separate PR would be great. It's okay if some or all of them produce ICEs in that PR, there's a tests/ui/crashes folder for that and we can add in a tests/ui/crashes/reborrow folder specifically for those.
  2. The work you've done on the well-formedness check (coherence/builtin.rs) deserves a separate PR. We can then build on top of that to improve the checking to get to the desired state of the well-formedness check containing all the check logic.
  3. A distant third is the MIR pass itself: this we'll be very deeply involved in so collaborating may be harder, but as we get into building the pass I can ping you or send an email and let you know if there is anything in particular you could help with.

On the communication front, I recommend using your own voice and words in the future: you're doing yourself a disfavour by using an LLM to translate and generate text for you. You do not need to communicate in perfect English - it's perfectly okay to communicate at the level that you're capable of, and nothing more or less.

Cheers.

View changes since this review

Hi, thanks so much. I appreciate it!

I am unfortunately a bit caught up with work at the moment. Thus, I dont think I will be doing more work soon. I will email you if I get a breather and can resume work on Reborrow. I also think that the above approach sounds great.

I have split this PR into #157490 and #157489 I am, however, uncertain if it is the exact split you want. Just say if I have to remove things

@P8L1 P8L1 closed this Jun 5, 2026
@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

F-reborrow `#![feature(reborrow)]`; see #145612 T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

10 participants