Add support for inline bounds

E.g. impl<T: Clone> Foo for T.
This commit is contained in:
Florian Diebold 2019-05-11 16:49:55 +02:00
parent d6dc75f9f2
commit cbe75676b9
2 changed files with 60 additions and 16 deletions

View file

@ -90,8 +90,17 @@ impl GenericParams {
fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) { fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) {
for (idx, type_param) in params.type_params().enumerate() { for (idx, type_param) in params.type_params().enumerate() {
let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing); let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing);
let param = GenericParam { idx: idx as u32 + start, name }; let param = GenericParam { idx: idx as u32 + start, name: name.clone() };
self.params.push(param); self.params.push(param);
let type_ref = TypeRef::Path(name.into());
for bound in type_param
.type_bound_list()
.iter()
.flat_map(|type_bound_list| type_bound_list.bounds())
{
self.add_where_predicate_from_bound(bound, type_ref.clone());
}
} }
} }
@ -101,26 +110,28 @@ impl GenericParams {
Some(type_ref) => type_ref, Some(type_ref) => type_ref,
None => continue, None => continue,
}; };
let type_ref = TypeRef::from_ast(type_ref);
for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
let path = bound self.add_where_predicate_from_bound(bound, type_ref.clone());
.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,
});
} }
} }
} }
fn add_where_predicate_from_bound(&mut self, bound: &ast::TypeBound, type_ref: TypeRef) {
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 => return,
};
self.where_predicates.push(WherePredicate { type_ref, trait_ref: path });
}
pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
self.params.iter().find(|p| &p.name == name) self.params.iter().find(|p| &p.name == name)
} }

View file

@ -2535,6 +2535,22 @@ fn test() { (&S).foo()<|>; }
assert_eq!(t, "{unknown}"); assert_eq!(t, "{unknown}");
} }
#[test]
fn method_resolution_where_clause_inline_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<T: Clone> Trait for T {}
fn test() { (&S).foo()<|>; }
"#,
);
assert_eq!(t, "{unknown}");
}
#[test] #[test]
fn method_resolution_where_clause_1() { fn method_resolution_where_clause_1() {
let t = type_at( let t = type_at(
@ -2568,6 +2584,23 @@ fn test() { S2.into()<|>; }
assert_eq!(t, "S1"); assert_eq!(t, "S1");
} }
#[test]
fn method_resolution_where_clause_inline() {
let t = type_at(
r#"
//- /main.rs
trait Into<T> { fn into(self) -> T; }
trait From<T> { fn from(other: T) -> Self; }
struct S1;
struct S2;
impl From<S2> for S1 {};
impl<T, U: From<T>> Into<U> for T {}
fn test() { S2.into()<|>; }
"#,
);
assert_eq!(t, "S1");
}
#[test] #[test]
fn method_resolution_encountering_fn_type() { fn method_resolution_encountering_fn_type() {
covers!(trait_resolution_on_fn_type); covers!(trait_resolution_on_fn_type);