Skip to content

Commit e313efb

Browse files
committed
Do array unsizing for method receivers
It turns out rustc actually only unsizes array method receivers, so we don't need to do any trait solving for this (at least for now). Fixes #2670.
1 parent 5e78036 commit e313efb

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

crates/ra_hir_ty/src/method_resolution.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::{
2020
db::HirDatabase,
2121
primitive::{FloatBitness, Uncertain},
2222
utils::all_super_traits,
23-
Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
23+
ApplicationTy, Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
2424
};
2525

2626
/// This is used as a key for indexing impls.
@@ -214,7 +214,7 @@ pub fn iterate_method_candidates<T>(
214214
// the methods by autoderef order of *receiver types*, not *self
215215
// types*.
216216

217-
let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect();
217+
let deref_chain = autoderef_method_receiver(db, krate, ty);
218218
for i in 0..deref_chain.len() {
219219
if let Some(result) = iterate_method_candidates_with_autoref(
220220
&deref_chain[i..],
@@ -548,3 +548,20 @@ fn generic_implements_goal(
548548
let obligation = super::Obligation::Trait(trait_ref);
549549
Canonical { num_vars, value: InEnvironment::new(env, obligation) }
550550
}
551+
552+
fn autoderef_method_receiver(
553+
db: &impl HirDatabase,
554+
krate: CrateId,
555+
ty: InEnvironment<Canonical<Ty>>,
556+
) -> Vec<Canonical<Ty>> {
557+
let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect();
558+
// As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
559+
if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) =
560+
deref_chain.last().map(|ty| &ty.value)
561+
{
562+
let num_vars = deref_chain.last().unwrap().num_vars;
563+
let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone());
564+
deref_chain.push(Canonical { value: unsized_ty, num_vars })
565+
}
566+
deref_chain
567+
}

crates/ra_hir_ty/src/tests/method_resolution.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,24 @@ fn test() { (&S).foo()<|>; }
838838
assert_eq!(t, "u128");
839839
}
840840

841+
#[test]
842+
fn method_resolution_unsize_array() {
843+
let t = type_at(
844+
r#"
845+
//- /main.rs
846+
#[lang = "slice"]
847+
impl<T> [T] {
848+
fn len(&self) -> usize { loop {} }
849+
}
850+
fn test() {
851+
let a = [1, 2, 3];
852+
a.len()<|>;
853+
}
854+
"#,
855+
);
856+
assert_eq!(t, "usize");
857+
}
858+
841859
#[test]
842860
fn method_resolution_trait_from_prelude() {
843861
let (db, pos) = TestDB::with_position(

0 commit comments

Comments
 (0)