2592: Add std::ops::Index support for infering r=edwin0cheng a=edwin0cheng

see also #2534

Seem like this can't fix #2534 for this case:

```rust
fn foo3(bar: [usize; 2]) {
    let baz = bar[1];   // <--- baz is still unknown ?
    println!("{}", baz);
}
```

Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
bors[bot] 2019-12-20 14:36:53 +00:00 committed by GitHub
commit d590f6ce12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 5 deletions

View file

@ -257,6 +257,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")
}; };

View file

@ -161,6 +161,7 @@ pub mod known {
Range, Range,
Neg, Neg,
Not, Not,
Index,
// Builtin macros // Builtin macros
file, file,
column, column,

View file

@ -363,14 +363,26 @@ 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 builder = Substs::build_for_def(self.db, res_assoc_ty)
.push(inner_ty)
.fill(params.iter().cloned());
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 +529,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

View file

@ -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 {

View file

@ -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(