mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
feat: Implement arbitrary-self-types
This commit is contained in:
parent
84d44d0a57
commit
f4dfbc38c8
@ -372,6 +372,7 @@ language_item_table! {
|
||||
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
|
||||
Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
|
||||
ReceiverTarget, sym::receiver_target, receiver_target, Target::AssocTy, GenericRequirement::None;
|
||||
|
||||
Fn, sym::fn_, fn_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
|
||||
|
@ -39,7 +39,7 @@ pub fn autoderef(
|
||||
) -> impl Iterator<Item = Ty> {
|
||||
let mut table = InferenceTable::new(db, env);
|
||||
let ty = table.instantiate_canonical(ty);
|
||||
let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false);
|
||||
let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false, false);
|
||||
let mut v = Vec::new();
|
||||
while let Some((ty, _steps)) = autoderef.next() {
|
||||
// `ty` may contain unresolved inference variables. Since there's no chance they would be
|
||||
@ -89,12 +89,18 @@ pub(crate) struct Autoderef<'table, 'db, T = Vec<(AutoderefKind, Ty)>> {
|
||||
at_start: bool,
|
||||
steps: T,
|
||||
explicit: bool,
|
||||
use_receiver_trait: bool,
|
||||
}
|
||||
|
||||
impl<'table, 'db> Autoderef<'table, 'db> {
|
||||
pub(crate) fn new(table: &'table mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self {
|
||||
pub(crate) fn new(
|
||||
table: &'table mut InferenceTable<'db>,
|
||||
ty: Ty,
|
||||
explicit: bool,
|
||||
use_receiver_trait: bool,
|
||||
) -> Self {
|
||||
let ty = table.resolve_ty_shallow(&ty);
|
||||
Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit }
|
||||
Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit, use_receiver_trait }
|
||||
}
|
||||
|
||||
pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] {
|
||||
@ -107,9 +113,10 @@ impl<'table, 'db> Autoderef<'table, 'db, usize> {
|
||||
table: &'table mut InferenceTable<'db>,
|
||||
ty: Ty,
|
||||
explicit: bool,
|
||||
use_receiver_trait: bool,
|
||||
) -> Self {
|
||||
let ty = table.resolve_ty_shallow(&ty);
|
||||
Autoderef { table, ty, at_start: true, steps: 0, explicit }
|
||||
Autoderef { table, ty, at_start: true, steps: 0, explicit, use_receiver_trait }
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,7 +144,8 @@ impl<T: TrackAutoderefSteps> Iterator for Autoderef<'_, '_, T> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (kind, new_ty) = autoderef_step(self.table, self.ty.clone(), self.explicit)?;
|
||||
let (kind, new_ty) =
|
||||
autoderef_step(self.table, self.ty.clone(), self.explicit, self.use_receiver_trait)?;
|
||||
|
||||
self.steps.push(kind, &self.ty);
|
||||
self.ty = new_ty;
|
||||
@ -150,11 +158,12 @@ pub(crate) fn autoderef_step(
|
||||
table: &mut InferenceTable<'_>,
|
||||
ty: Ty,
|
||||
explicit: bool,
|
||||
use_receiver_trait: bool,
|
||||
) -> Option<(AutoderefKind, Ty)> {
|
||||
if let Some(derefed) = builtin_deref(table.db, &ty, explicit) {
|
||||
Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
|
||||
} else {
|
||||
Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
|
||||
Some((AutoderefKind::Overloaded, deref_by_trait(table, ty, use_receiver_trait)?))
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,6 +185,7 @@ pub(crate) fn builtin_deref<'ty>(
|
||||
pub(crate) fn deref_by_trait(
|
||||
table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>,
|
||||
ty: Ty,
|
||||
use_receiver_trait: bool,
|
||||
) -> Option<Ty> {
|
||||
let _p = tracing::info_span!("deref_by_trait").entered();
|
||||
if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() {
|
||||
@ -183,14 +193,25 @@ pub(crate) fn deref_by_trait(
|
||||
return None;
|
||||
}
|
||||
|
||||
let deref_trait =
|
||||
db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?;
|
||||
let trait_id = || {
|
||||
if use_receiver_trait {
|
||||
if let Some(receiver) =
|
||||
db.lang_item(table.trait_env.krate, LangItem::Receiver).and_then(|l| l.as_trait())
|
||||
{
|
||||
return Some(receiver);
|
||||
}
|
||||
}
|
||||
// Old rustc versions might not have `Receiver` trait.
|
||||
// Fallback to `Deref` if they don't
|
||||
db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())
|
||||
};
|
||||
let trait_id = trait_id()?;
|
||||
let target = db
|
||||
.trait_data(deref_trait)
|
||||
.trait_data(trait_id)
|
||||
.associated_type_by_name(&Name::new_symbol_root(sym::Target.clone()))?;
|
||||
|
||||
let projection = {
|
||||
let b = TyBuilder::subst_for_def(db, deref_trait, None);
|
||||
let b = TyBuilder::subst_for_def(db, trait_id, None);
|
||||
if b.remaining() != 1 {
|
||||
// the Target type + Deref trait should only have one generic parameter,
|
||||
// namely Deref's Self type
|
||||
|
@ -420,7 +420,7 @@ impl InferenceTable<'_> {
|
||||
|
||||
let snapshot = self.snapshot();
|
||||
|
||||
let mut autoderef = Autoderef::new(self, from_ty.clone(), false);
|
||||
let mut autoderef = Autoderef::new(self, from_ty.clone(), false, false);
|
||||
let mut first_error = None;
|
||||
let mut found = None;
|
||||
|
||||
|
@ -487,7 +487,7 @@ impl InferenceContext<'_> {
|
||||
}
|
||||
Expr::Call { callee, args, .. } => {
|
||||
let callee_ty = self.infer_expr(*callee, &Expectation::none(), ExprIsRead::Yes);
|
||||
let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false);
|
||||
let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false, true);
|
||||
let (res, derefed_callee) = loop {
|
||||
let Some((callee_deref_ty, _)) = derefs.next() else {
|
||||
break (None, callee_ty.clone());
|
||||
@ -854,7 +854,7 @@ impl InferenceContext<'_> {
|
||||
if let Some(derefed) = builtin_deref(self.table.db, &inner_ty, true) {
|
||||
self.resolve_ty_shallow(derefed)
|
||||
} else {
|
||||
deref_by_trait(&mut self.table, inner_ty)
|
||||
deref_by_trait(&mut self.table, inner_ty, false)
|
||||
.unwrap_or_else(|| self.err_ty())
|
||||
}
|
||||
}
|
||||
@ -1718,7 +1718,7 @@ impl InferenceContext<'_> {
|
||||
receiver_ty: &Ty,
|
||||
name: &Name,
|
||||
) -> Option<(Ty, Either<FieldId, TupleFieldId>, Vec<Adjustment>, bool)> {
|
||||
let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false);
|
||||
let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false, false);
|
||||
let mut private_field = None;
|
||||
let res = autoderef.by_ref().find_map(|(derefed_ty, _)| {
|
||||
let (field_id, parameters) = match derefed_ty.kind(Interner) {
|
||||
|
@ -528,7 +528,7 @@ impl ReceiverAdjustments {
|
||||
let mut ty = table.resolve_ty_shallow(&ty);
|
||||
let mut adjust = Vec::new();
|
||||
for _ in 0..self.autoderefs {
|
||||
match autoderef::autoderef_step(table, ty.clone(), true) {
|
||||
match autoderef::autoderef_step(table, ty.clone(), true, false) {
|
||||
None => {
|
||||
never!("autoderef not possible for {:?}", ty);
|
||||
ty = TyKind::Error.intern(Interner);
|
||||
@ -1106,7 +1106,8 @@ fn iterate_method_candidates_by_receiver(
|
||||
// be found in any of the derefs of receiver_ty, so we have to go through
|
||||
// that, including raw derefs.
|
||||
table.run_in_snapshot(|table| {
|
||||
let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
|
||||
let mut autoderef =
|
||||
autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true);
|
||||
while let Some((self_ty, _)) = autoderef.next() {
|
||||
iterate_inherent_methods(
|
||||
&self_ty,
|
||||
@ -1123,7 +1124,8 @@ fn iterate_method_candidates_by_receiver(
|
||||
ControlFlow::Continue(())
|
||||
})?;
|
||||
table.run_in_snapshot(|table| {
|
||||
let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
|
||||
let mut autoderef =
|
||||
autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true);
|
||||
while let Some((self_ty, _)) = autoderef.next() {
|
||||
if matches!(self_ty.kind(Interner), TyKind::InferenceVar(_, TyVariableKind::General)) {
|
||||
// don't try to resolve methods on unknown types
|
||||
@ -1709,7 +1711,7 @@ fn autoderef_method_receiver(
|
||||
ty: Ty,
|
||||
) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
|
||||
let mut deref_chain: Vec<_> = Vec::new();
|
||||
let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false);
|
||||
let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false, true);
|
||||
while let Some((ty, derefs)) = autoderef.next() {
|
||||
deref_chain.push((
|
||||
autoderef.table.canonicalize(ty),
|
||||
|
@ -1343,7 +1343,7 @@ fn foo<T: Trait>(a: &T) {
|
||||
fn autoderef_visibility_field() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
//- minicore: receiver
|
||||
mod a {
|
||||
pub struct Foo(pub char);
|
||||
pub struct Bar(i32);
|
||||
@ -1375,7 +1375,7 @@ fn autoderef_visibility_method() {
|
||||
cov_mark::check!(autoderef_candidate_not_visible);
|
||||
check(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
//- minicore: receiver
|
||||
mod a {
|
||||
pub struct Foo(pub char);
|
||||
impl Foo {
|
||||
@ -1741,7 +1741,7 @@ fn main() {
|
||||
fn deref_fun_1() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
//- minicore: receiver
|
||||
|
||||
struct A<T, U>(T, U);
|
||||
struct B<T>(T);
|
||||
@ -1782,7 +1782,7 @@ fn test() {
|
||||
fn deref_fun_2() {
|
||||
check_types(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
//- minicore: receiver
|
||||
|
||||
struct A<T, U>(T, U);
|
||||
struct B<T>(T);
|
||||
@ -1903,7 +1903,7 @@ pub fn test(generic_args: impl Into<Foo>) {
|
||||
fn bad_inferred_reference_2() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
//- minicore: receiver
|
||||
trait ExactSizeIterator {
|
||||
fn len(&self) -> usize;
|
||||
}
|
||||
@ -2054,7 +2054,7 @@ fn foo() {
|
||||
fn box_deref_is_builtin() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
//- minicore: receiver
|
||||
use core::ops::Deref;
|
||||
|
||||
#[lang = "owned_box"]
|
||||
@ -2087,7 +2087,7 @@ fn test() {
|
||||
fn manually_drop_deref_is_not_builtin() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: manually_drop, deref
|
||||
//- minicore: manually_drop, receiver
|
||||
struct Foo;
|
||||
impl Foo {
|
||||
fn foo(&self) {}
|
||||
@ -2105,7 +2105,7 @@ fn test() {
|
||||
fn mismatched_args_due_to_supertraits_with_deref() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
//- minicore: deref
|
||||
//- minicore: receiver
|
||||
use core::ops::Deref;
|
||||
|
||||
trait Trait1 {
|
||||
@ -2139,3 +2139,34 @@ fn problem_method<T: Trait3>() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn receiver_without_deref_impl() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: receiver
|
||||
use core::ops::Receiver;
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn foo1(self: &Bar) -> i32 { 42 }
|
||||
fn foo2(self: Bar) -> bool { true }
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Receiver for Bar {
|
||||
type Target = Foo;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let bar = Bar;
|
||||
let _v1 = bar.foo1();
|
||||
//^^^ type: i32
|
||||
let _v2 = bar.foo2();
|
||||
//^^^ type: bool
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -1466,4 +1466,34 @@ async fn bar() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn receiver_without_deref_impl_completion() {
|
||||
check_no_kw(
|
||||
r#"
|
||||
//- minicore: receiver
|
||||
use core::ops::Receiver;
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn foo(self: Bar) {}
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Receiver for Bar {
|
||||
type Target = Foo;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let bar = Bar;
|
||||
bar.$0
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(self: Bar)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -394,6 +394,7 @@ define_symbols! {
|
||||
RangeToInclusive,
|
||||
Ready,
|
||||
receiver,
|
||||
receiver_target,
|
||||
recursion_limit,
|
||||
register_attr,
|
||||
register_tool,
|
||||
|
@ -53,6 +53,7 @@
|
||||
//! pin:
|
||||
//! pointee: copy, send, sync, ord, hash, unpin
|
||||
//! range:
|
||||
//! receiver: deref
|
||||
//! result:
|
||||
//! send: sized
|
||||
//! size_of: sized
|
||||
@ -513,10 +514,26 @@ pub mod ops {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target;
|
||||
}
|
||||
// endregion:deref_mut
|
||||
|
||||
// region:receiver
|
||||
#[lang = "receiver"]
|
||||
pub trait Receiver {
|
||||
#[lang = "receiver_target"]
|
||||
type Target: ?Sized;
|
||||
}
|
||||
|
||||
impl<P: ?Sized, T: ?Sized> Receiver for P
|
||||
where
|
||||
P: Deref<Target = T>,
|
||||
{
|
||||
type Target = T;
|
||||
}
|
||||
// endregion:receiver
|
||||
}
|
||||
pub use self::deref::{
|
||||
Deref,
|
||||
DerefMut, // :deref_mut
|
||||
Receiver, // :receiver
|
||||
};
|
||||
// endregion:deref
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user