Follow raw pointers in autoderef chain when resolving methods with custom receiver
This commit is contained in:
parent
246d11b2a5
commit
5991f0d869
@ -36,7 +36,7 @@ pub fn autoderef(
|
|||||||
) -> impl Iterator<Item = Ty> {
|
) -> impl Iterator<Item = Ty> {
|
||||||
let mut table = InferenceTable::new(db, env);
|
let mut table = InferenceTable::new(db, env);
|
||||||
let ty = table.instantiate_canonical(ty);
|
let ty = table.instantiate_canonical(ty);
|
||||||
let mut autoderef = Autoderef::new(&mut table, ty);
|
let mut autoderef = Autoderef::new(&mut table, ty, false);
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
while let Some((ty, _steps)) = autoderef.next() {
|
while let Some((ty, _steps)) = autoderef.next() {
|
||||||
// `ty` may contain unresolved inference variables. Since there's no chance they would be
|
// `ty` may contain unresolved inference variables. Since there's no chance they would be
|
||||||
@ -63,12 +63,13 @@ pub(crate) struct Autoderef<'a, 'db> {
|
|||||||
ty: Ty,
|
ty: Ty,
|
||||||
at_start: bool,
|
at_start: bool,
|
||||||
steps: Vec<(AutoderefKind, Ty)>,
|
steps: Vec<(AutoderefKind, Ty)>,
|
||||||
|
explicit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'db> Autoderef<'a, 'db> {
|
impl<'a, 'db> Autoderef<'a, 'db> {
|
||||||
pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty) -> Self {
|
pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self {
|
||||||
let ty = table.resolve_ty_shallow(&ty);
|
let ty = table.resolve_ty_shallow(&ty);
|
||||||
Autoderef { table, ty, at_start: true, steps: Vec::new() }
|
Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn step_count(&self) -> usize {
|
pub(crate) fn step_count(&self) -> usize {
|
||||||
@ -97,7 +98,7 @@ impl Iterator for Autoderef<'_, '_> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (kind, new_ty) = autoderef_step(self.table, self.ty.clone())?;
|
let (kind, new_ty) = autoderef_step(self.table, self.ty.clone(), self.explicit)?;
|
||||||
|
|
||||||
self.steps.push((kind, self.ty.clone()));
|
self.steps.push((kind, self.ty.clone()));
|
||||||
self.ty = new_ty;
|
self.ty = new_ty;
|
||||||
@ -109,8 +110,9 @@ impl Iterator for Autoderef<'_, '_> {
|
|||||||
pub(crate) fn autoderef_step(
|
pub(crate) fn autoderef_step(
|
||||||
table: &mut InferenceTable<'_>,
|
table: &mut InferenceTable<'_>,
|
||||||
ty: Ty,
|
ty: Ty,
|
||||||
|
explicit: bool,
|
||||||
) -> Option<(AutoderefKind, Ty)> {
|
) -> Option<(AutoderefKind, Ty)> {
|
||||||
if let Some(derefed) = builtin_deref(table, &ty, false) {
|
if let Some(derefed) = builtin_deref(table, &ty, explicit) {
|
||||||
Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
|
Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
|
||||||
} else {
|
} else {
|
||||||
Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
|
Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
|
||||||
@ -124,7 +126,6 @@ pub(crate) fn builtin_deref<'ty>(
|
|||||||
) -> Option<&'ty Ty> {
|
) -> Option<&'ty Ty> {
|
||||||
match ty.kind(Interner) {
|
match ty.kind(Interner) {
|
||||||
TyKind::Ref(.., ty) => Some(ty),
|
TyKind::Ref(.., ty) => Some(ty),
|
||||||
// FIXME: Maybe accept this but diagnose if its not explicit?
|
|
||||||
TyKind::Raw(.., ty) if explicit => Some(ty),
|
TyKind::Raw(.., ty) if explicit => Some(ty),
|
||||||
&TyKind::Adt(chalk_ir::AdtId(adt), ref substs) => {
|
&TyKind::Adt(chalk_ir::AdtId(adt), ref substs) => {
|
||||||
if crate::lang_items::is_box(table.db, adt) {
|
if crate::lang_items::is_box(table.db, adt) {
|
||||||
|
@ -377,7 +377,7 @@ impl<'a> InferenceTable<'a> {
|
|||||||
|
|
||||||
let snapshot = self.snapshot();
|
let snapshot = self.snapshot();
|
||||||
|
|
||||||
let mut autoderef = Autoderef::new(self, from_ty.clone());
|
let mut autoderef = Autoderef::new(self, from_ty.clone(), false);
|
||||||
let mut first_error = None;
|
let mut first_error = None;
|
||||||
let mut found = None;
|
let mut found = None;
|
||||||
|
|
||||||
|
@ -316,7 +316,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
}
|
}
|
||||||
Expr::Call { callee, args, .. } => {
|
Expr::Call { callee, args, .. } => {
|
||||||
let callee_ty = self.infer_expr(*callee, &Expectation::none());
|
let callee_ty = self.infer_expr(*callee, &Expectation::none());
|
||||||
let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone());
|
let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false);
|
||||||
let (res, derefed_callee) = 'b: {
|
let (res, derefed_callee) = 'b: {
|
||||||
// manual loop to be able to access `derefs.table`
|
// manual loop to be able to access `derefs.table`
|
||||||
while let Some((callee_deref_ty, _)) = derefs.next() {
|
while let Some((callee_deref_ty, _)) = derefs.next() {
|
||||||
@ -1385,7 +1385,7 @@ impl<'a> InferenceContext<'a> {
|
|||||||
receiver_ty: &Ty,
|
receiver_ty: &Ty,
|
||||||
name: &Name,
|
name: &Name,
|
||||||
) -> Option<(Ty, Option<FieldId>, Vec<Adjustment>, bool)> {
|
) -> Option<(Ty, Option<FieldId>, Vec<Adjustment>, bool)> {
|
||||||
let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone());
|
let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false);
|
||||||
let mut private_field = None;
|
let mut private_field = None;
|
||||||
let res = autoderef.by_ref().find_map(|(derefed_ty, _)| {
|
let res = autoderef.by_ref().find_map(|(derefed_ty, _)| {
|
||||||
let (field_id, parameters) = match derefed_ty.kind(Interner) {
|
let (field_id, parameters) = match derefed_ty.kind(Interner) {
|
||||||
|
@ -534,7 +534,7 @@ impl ReceiverAdjustments {
|
|||||||
let mut ty = table.resolve_ty_shallow(&ty);
|
let mut ty = table.resolve_ty_shallow(&ty);
|
||||||
let mut adjust = Vec::new();
|
let mut adjust = Vec::new();
|
||||||
for _ in 0..self.autoderefs {
|
for _ in 0..self.autoderefs {
|
||||||
match autoderef::autoderef_step(table, ty.clone()) {
|
match autoderef::autoderef_step(table, ty.clone(), true) {
|
||||||
None => {
|
None => {
|
||||||
never!("autoderef not possible for {:?}", ty);
|
never!("autoderef not possible for {:?}", ty);
|
||||||
ty = TyKind::Error.intern(Interner);
|
ty = TyKind::Error.intern(Interner);
|
||||||
@ -1012,8 +1012,8 @@ fn iterate_method_candidates_by_receiver(
|
|||||||
let snapshot = table.snapshot();
|
let snapshot = table.snapshot();
|
||||||
// We're looking for methods with *receiver* type receiver_ty. These could
|
// We're looking for methods with *receiver* type receiver_ty. These could
|
||||||
// be found in any of the derefs of receiver_ty, so we have to go through
|
// be found in any of the derefs of receiver_ty, so we have to go through
|
||||||
// that.
|
// that, including raw derefs.
|
||||||
let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
|
let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone(), true);
|
||||||
while let Some((self_ty, _)) = autoderef.next() {
|
while let Some((self_ty, _)) = autoderef.next() {
|
||||||
iterate_inherent_methods(
|
iterate_inherent_methods(
|
||||||
&self_ty,
|
&self_ty,
|
||||||
@ -1028,7 +1028,7 @@ fn iterate_method_candidates_by_receiver(
|
|||||||
|
|
||||||
table.rollback_to(snapshot);
|
table.rollback_to(snapshot);
|
||||||
|
|
||||||
let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
|
let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone(), true);
|
||||||
while let Some((self_ty, _)) = autoderef.next() {
|
while let Some((self_ty, _)) = autoderef.next() {
|
||||||
iterate_trait_method_candidates(
|
iterate_trait_method_candidates(
|
||||||
&self_ty,
|
&self_ty,
|
||||||
@ -1504,7 +1504,7 @@ fn autoderef_method_receiver(
|
|||||||
ty: Ty,
|
ty: Ty,
|
||||||
) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
|
) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
|
||||||
let mut deref_chain: Vec<_> = Vec::new();
|
let mut deref_chain: Vec<_> = Vec::new();
|
||||||
let mut autoderef = autoderef::Autoderef::new(table, ty);
|
let mut autoderef = autoderef::Autoderef::new(table, ty, true);
|
||||||
while let Some((ty, derefs)) = autoderef.next() {
|
while let Some((ty, derefs)) = autoderef.next() {
|
||||||
deref_chain.push((
|
deref_chain.push((
|
||||||
autoderef.table.canonicalize(ty).value,
|
autoderef.table.canonicalize(ty).value,
|
||||||
|
@ -1215,6 +1215,52 @@ fn main() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inherent_method_deref_raw() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
struct Val;
|
||||||
|
|
||||||
|
impl Val {
|
||||||
|
pub fn method(self: *const Val) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo: *const Val;
|
||||||
|
foo.method();
|
||||||
|
// ^^^^^^^^^^^^ u32
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trait_method_deref_raw() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
trait Trait {
|
||||||
|
fn method(self: *const Self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Val;
|
||||||
|
|
||||||
|
impl Trait for Val {
|
||||||
|
fn method(self: *const Self) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo: *const Val;
|
||||||
|
foo.method();
|
||||||
|
// ^^^^^^^^^^^^ u32
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn method_on_dyn_impl() {
|
fn method_on_dyn_impl() {
|
||||||
check_types(
|
check_types(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user