mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 05:15:04 +00:00
Add std::ops::Index support for infering
This commit is contained in:
parent
242f0ae1d8
commit
dddee23f43
5 changed files with 63 additions and 5 deletions
|
@ -254,6 +254,7 @@ macro_rules! __known_path {
|
||||||
(std::ops::Try) => {};
|
(std::ops::Try) => {};
|
||||||
(std::ops::Neg) => {};
|
(std::ops::Neg) => {};
|
||||||
(std::ops::Not) => {};
|
(std::ops::Not) => {};
|
||||||
|
(std::ops::Index) => {};
|
||||||
($path:path) => {
|
($path:path) => {
|
||||||
compile_error!("Please register your known path in the path module")
|
compile_error!("Please register your known path in the path module")
|
||||||
};
|
};
|
||||||
|
|
|
@ -161,6 +161,7 @@ pub mod known {
|
||||||
Range,
|
Range,
|
||||||
Neg,
|
Neg,
|
||||||
Not,
|
Not,
|
||||||
|
Index,
|
||||||
// Builtin macros
|
// Builtin macros
|
||||||
file,
|
file,
|
||||||
column,
|
column,
|
||||||
|
|
|
@ -363,14 +363,28 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
|
fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
|
||||||
|
self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_associated_type_with_params(
|
||||||
|
&mut self,
|
||||||
|
inner_ty: Ty,
|
||||||
|
assoc_ty: Option<TypeAliasId>,
|
||||||
|
params: &[Ty],
|
||||||
|
) -> Ty {
|
||||||
match assoc_ty {
|
match assoc_ty {
|
||||||
Some(res_assoc_ty) => {
|
Some(res_assoc_ty) => {
|
||||||
let ty = self.table.new_type_var();
|
let ty = self.table.new_type_var();
|
||||||
|
let mut builder = Substs::builder(1 + params.len()).push(inner_ty);
|
||||||
|
for ty in params {
|
||||||
|
builder = builder.push(ty.clone());
|
||||||
|
}
|
||||||
|
|
||||||
let projection = ProjectionPredicate {
|
let projection = ProjectionPredicate {
|
||||||
ty: ty.clone(),
|
ty: ty.clone(),
|
||||||
projection_ty: ProjectionTy {
|
projection_ty: ProjectionTy {
|
||||||
associated_ty: res_assoc_ty,
|
associated_ty: res_assoc_ty,
|
||||||
parameters: Substs::single(inner_ty),
|
parameters: builder.build(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
self.obligations.push(Obligation::Projection(projection));
|
self.obligations.push(Obligation::Projection(projection));
|
||||||
|
@ -517,6 +531,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
|
let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
|
||||||
Some(struct_.into())
|
Some(struct_.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
|
||||||
|
let path = path![std::ops::Index];
|
||||||
|
let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
|
||||||
|
self.db.trait_data(trait_).associated_type_by_name(&name![Output])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The kinds of placeholders we need during type inference. There's separate
|
/// The kinds of placeholders we need during type inference. There's separate
|
||||||
|
|
|
@ -422,10 +422,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Index { base, index } => {
|
Expr::Index { base, index } => {
|
||||||
let _base_ty = self.infer_expr_inner(*base, &Expectation::none());
|
let base_ty = self.infer_expr_inner(*base, &Expectation::none());
|
||||||
let _index_ty = self.infer_expr(*index, &Expectation::none());
|
let index_ty = self.infer_expr(*index, &Expectation::none());
|
||||||
// FIXME: use `std::ops::Index::Output` to figure out the real return type
|
|
||||||
Ty::Unknown
|
self.resolve_associated_type_with_params(
|
||||||
|
base_ty,
|
||||||
|
self.resolve_ops_index_output(),
|
||||||
|
&[index_ty],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Expr::Tuple { exprs } => {
|
Expr::Tuple { exprs } => {
|
||||||
let mut tys = match &expected.ty {
|
let mut tys = match &expected.ty {
|
||||||
|
|
|
@ -426,6 +426,38 @@ fn indexing_arrays() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_ops_index() {
|
||||||
|
let (db, pos) = TestDB::with_position(
|
||||||
|
r#"
|
||||||
|
//- /main.rs crate:main deps:std
|
||||||
|
|
||||||
|
struct Bar;
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
impl std::ops::Index<u32> for Bar {
|
||||||
|
type Output = Foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let a = Bar;
|
||||||
|
let b = a[1];
|
||||||
|
b<|>;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- /std.rs crate:std
|
||||||
|
|
||||||
|
#[prelude_import] use ops::*;
|
||||||
|
mod ops {
|
||||||
|
pub trait Index<Idx> {
|
||||||
|
type Output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
assert_eq!("Foo", type_at_pos(&db, pos));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn deref_trait() {
|
fn deref_trait() {
|
||||||
let t = type_at(
|
let t = type_at(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue