fix: Implement mut to const ptr cast for method resolution

This commit is contained in:
Shoyu Vanilla 2025-05-03 03:00:49 +09:00
parent be7433328e
commit 4aa98bf1d7
2 changed files with 82 additions and 13 deletions

View File

@ -515,9 +515,15 @@ impl From<Option<BlockId>> for VisibleFromModule {
}
}
#[derive(Debug, Clone)]
pub enum AutorefOrPtrAdjustment {
Autoref(Mutability),
ToConstPtr,
}
#[derive(Debug, Clone, Default)]
pub struct ReceiverAdjustments {
autoref: Option<Mutability>,
autoref: Option<AutorefOrPtrAdjustment>,
autoderefs: usize,
unsize_array: bool,
}
@ -535,10 +541,15 @@ impl ReceiverAdjustments {
}
Some((kind, new_ty)) => {
ty = new_ty.clone();
let mutbl = match self.autoref {
Some(AutorefOrPtrAdjustment::Autoref(m)) => Some(m),
Some(AutorefOrPtrAdjustment::ToConstPtr) => Some(Mutability::Not),
// FIXME should we know the mutability here, when autoref is `None`?
None => None,
};
adjust.push(Adjustment {
kind: Adjust::Deref(match kind {
// FIXME should we know the mutability here, when autoref is `None`?
AutoderefKind::Overloaded => Some(OverloadedDeref(self.autoref)),
AutoderefKind::Overloaded => Some(OverloadedDeref(mutbl)),
AutoderefKind::Builtin => None,
}),
target: new_ty,
@ -546,11 +557,27 @@ impl ReceiverAdjustments {
}
}
}
if let Some(m) = self.autoref {
if let Some(autoref) = &self.autoref {
let lt = table.new_lifetime_var();
let a = Adjustment::borrow(m, ty, lt);
ty = a.target.clone();
adjust.push(a);
match autoref {
AutorefOrPtrAdjustment::Autoref(m) => {
let a = Adjustment::borrow(*m, ty, lt);
ty = a.target.clone();
adjust.push(a);
}
AutorefOrPtrAdjustment::ToConstPtr => {
if let TyKind::Raw(Mutability::Mut, pointee) = ty.kind(Interner) {
let a = Adjustment {
kind: Adjust::Pointer(PointerCast::MutToConstPointer),
target: TyKind::Raw(Mutability::Not, pointee.clone()).intern(Interner),
};
ty = a.target.clone();
adjust.push(a);
} else {
never!("`ToConstPtr` target is not a raw mutable pointer");
}
}
};
}
if self.unsize_array {
ty = 'it: {
@ -575,8 +602,8 @@ impl ReceiverAdjustments {
(ty, adjust)
}
fn with_autoref(&self, m: Mutability) -> ReceiverAdjustments {
Self { autoref: Some(m), ..*self }
fn with_autoref(&self, a: AutorefOrPtrAdjustment) -> ReceiverAdjustments {
Self { autoref: Some(a), ..*self }
}
}
@ -1051,7 +1078,7 @@ fn iterate_method_candidates_with_autoref(
let mut maybe_reborrowed = first_adjustment.clone();
if let Some((_, _, m)) = receiver_ty.value.as_reference() {
// Prefer reborrow of references to move
maybe_reborrowed.autoref = Some(m);
maybe_reborrowed.autoref = Some(AutorefOrPtrAdjustment::Autoref(m));
maybe_reborrowed.autoderefs += 1;
}
@ -1063,15 +1090,34 @@ fn iterate_method_candidates_with_autoref(
binders: receiver_ty.binders.clone(),
};
iterate_method_candidates_by_receiver(refed, first_adjustment.with_autoref(Mutability::Not))?;
iterate_method_candidates_by_receiver(
refed,
first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Not)),
)?;
let ref_muted = Canonical {
value: TyKind::Ref(Mutability::Mut, error_lifetime(), receiver_ty.value.clone())
.intern(Interner),
binders: receiver_ty.binders,
binders: receiver_ty.binders.clone(),
};
iterate_method_candidates_by_receiver(ref_muted, first_adjustment.with_autoref(Mutability::Mut))
iterate_method_candidates_by_receiver(
ref_muted,
first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Mut)),
)?;
if let Some((ty, Mutability::Mut)) = receiver_ty.value.as_raw_ptr() {
let const_ptr_ty = Canonical {
value: TyKind::Raw(Mutability::Not, ty.clone()).intern(Interner),
binders: receiver_ty.binders,
};
iterate_method_candidates_by_receiver(
const_ptr_ty,
first_adjustment.with_autoref(AutorefOrPtrAdjustment::ToConstPtr),
)?;
}
ControlFlow::Continue(())
}
pub trait MethodCandidateCallback {

View File

@ -2170,3 +2170,26 @@ fn main() {
"#,
);
}
#[test]
fn mut_to_const_pointer() {
check(
r#"
pub trait X {
fn perform(self) -> u64;
}
impl X for *const u8 {
fn perform(self) -> u64 {
42
}
}
fn test(x: *mut u8) {
let _v = x.perform();
// ^ adjustments: Pointer(MutToConstPointer)
// ^^^^^^^^^^^ type: u64
}
"#,
);
}