mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Merge #1182
1182: Add HIR for where clauses & ignore impls with where clauses in trait resolution r=matklad a=flodiebold This prevents any `impl<T> Trait for T where ...` from being treated as a blanket impl while we don't handle where clauses yet. Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
commit
5e1c29543c
3 changed files with 63 additions and 5 deletions
|
@ -5,11 +5,11 @@
|
|||
|
||||
use std::sync::Arc;
|
||||
|
||||
use ra_syntax::ast::{self, NameOwner, TypeParamsOwner};
|
||||
use ra_syntax::ast::{self, NameOwner, TypeParamsOwner, TypeBoundsOwner};
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase,
|
||||
Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock, Container
|
||||
Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock, Container, path::Path, type_ref::TypeRef
|
||||
};
|
||||
|
||||
/// Data about a generic parameter (to a function, struct, impl, ...).
|
||||
|
@ -25,6 +25,15 @@ pub struct GenericParam {
|
|||
pub struct GenericParams {
|
||||
pub(crate) parent_params: Option<Arc<GenericParams>>,
|
||||
pub(crate) params: Vec<GenericParam>,
|
||||
pub(crate) where_predicates: Vec<WherePredicate>,
|
||||
}
|
||||
|
||||
/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
|
||||
/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct WherePredicate {
|
||||
type_ref: TypeRef,
|
||||
trait_ref: Path,
|
||||
}
|
||||
|
||||
// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
|
||||
|
@ -73,6 +82,9 @@ impl GenericParams {
|
|||
if let Some(params) = node.type_param_list() {
|
||||
self.fill_params(params, start)
|
||||
}
|
||||
if let Some(where_clause) = node.where_clause() {
|
||||
self.fill_where_predicates(where_clause);
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) {
|
||||
|
@ -83,6 +95,32 @@ impl GenericParams {
|
|||
}
|
||||
}
|
||||
|
||||
fn fill_where_predicates(&mut self, where_clause: &ast::WhereClause) {
|
||||
for pred in where_clause.predicates() {
|
||||
let type_ref = match pred.type_ref() {
|
||||
Some(type_ref) => type_ref,
|
||||
None => continue,
|
||||
};
|
||||
for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
|
||||
let path = bound
|
||||
.type_ref()
|
||||
.and_then(|tr| match tr.kind() {
|
||||
ast::TypeRefKind::PathType(path) => path.path(),
|
||||
_ => None,
|
||||
})
|
||||
.and_then(Path::from_ast);
|
||||
let path = match path {
|
||||
Some(p) => p,
|
||||
None => continue,
|
||||
};
|
||||
self.where_predicates.push(WherePredicate {
|
||||
type_ref: TypeRef::from_ast(type_ref),
|
||||
trait_ref: path,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
|
||||
self.params.iter().find(|p| &p.name == name)
|
||||
}
|
||||
|
|
|
@ -2477,6 +2477,23 @@ fn test() { (&S).foo()<|>; }
|
|||
assert_eq!(t, "u128");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn method_resolution_where_clause_not_met() {
|
||||
// The blanket impl shouldn't apply because we can't prove S: Clone
|
||||
let t = type_at(
|
||||
r#"
|
||||
//- /main.rs
|
||||
trait Clone {}
|
||||
trait Trait { fn foo(self) -> u128; }
|
||||
struct S;
|
||||
impl S { fn foo(self) -> i8 { 0 } }
|
||||
impl<T> Trait for T where T: Clone { fn foo(self) -> u128 { 0 } }
|
||||
fn test() { (&S).foo()<|>; }
|
||||
"#,
|
||||
);
|
||||
assert_eq!(t, "i8");
|
||||
}
|
||||
|
||||
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
||||
let file = db.parse(pos.file_id);
|
||||
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
//! Stuff that will probably mostly replaced by Chalk.
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::db::HirDatabase;
|
||||
use super::{ TraitRef, Substs, infer::{ TypeVarId, InferTy}, Ty};
|
||||
use crate::{db::HirDatabase, generics::HasGenericParams};
|
||||
use super::{TraitRef, Substs, infer::{TypeVarId, InferTy}, Ty};
|
||||
|
||||
// Copied (and simplified) from Chalk
|
||||
|
||||
|
@ -59,7 +59,10 @@ pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> Option<S
|
|||
None => return None,
|
||||
};
|
||||
let crate_impl_blocks = db.impls_in_crate(krate);
|
||||
let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_);
|
||||
let mut impl_blocks = crate_impl_blocks
|
||||
.lookup_impl_blocks_for_trait(&trait_ref.trait_)
|
||||
// we don't handle where clauses at all, waiting for Chalk for that
|
||||
.filter(|impl_block| impl_block.generic_params(db).where_predicates.is_empty());
|
||||
impl_blocks
|
||||
.find_map(|impl_block| unify_trait_refs(&trait_ref, &impl_block.target_trait_ref(db)?))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue