Use traits from prelude for method resolution
This commit is contained in:
parent
7fda874dd4
commit
bc59f83991
3 changed files with 42 additions and 14 deletions
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use ra_syntax::ast;
|
use ra_syntax::ast;
|
||||||
|
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ModuleDef, Trait,
|
ModuleDef, Trait,
|
||||||
|
@ -193,19 +193,18 @@ impl Resolver {
|
||||||
names
|
names
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn traits_in_scope<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
|
pub(crate) fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<Trait> {
|
||||||
// FIXME prelude
|
let mut traits = FxHashSet::default();
|
||||||
self.scopes
|
for scope in &self.scopes {
|
||||||
.iter()
|
if let Scope::ModuleScope(m) = scope {
|
||||||
.rev()
|
if let Some(prelude) = m.crate_def_map.prelude() {
|
||||||
.flat_map(|scope| {
|
let prelude_def_map = db.crate_def_map(prelude.krate);
|
||||||
match scope {
|
traits.extend(prelude_def_map[prelude.module_id].scope.traits());
|
||||||
Scope::ModuleScope(m) => Some(m.crate_def_map[m.module_id].scope.traits()),
|
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
.into_iter()
|
traits.extend(m.crate_def_map[m.module_id].scope.traits());
|
||||||
})
|
}
|
||||||
.flatten()
|
}
|
||||||
|
traits
|
||||||
}
|
}
|
||||||
|
|
||||||
fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
|
fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
|
||||||
|
|
|
@ -185,7 +185,7 @@ fn iterate_trait_method_candidates<T>(
|
||||||
mut callback: impl FnMut(&Ty, Function) -> Option<T>,
|
mut callback: impl FnMut(&Ty, Function) -> Option<T>,
|
||||||
) -> Option<T> {
|
) -> Option<T> {
|
||||||
let krate = resolver.krate()?;
|
let krate = resolver.krate()?;
|
||||||
'traits: for t in resolver.traits_in_scope() {
|
'traits: for t in resolver.traits_in_scope(db) {
|
||||||
let data = t.trait_data(db);
|
let data = t.trait_data(db);
|
||||||
// we'll be lazy about checking whether the type implements the
|
// we'll be lazy about checking whether the type implements the
|
||||||
// trait, but if we find out it doesn't, we'll skip the rest of the
|
// trait, but if we find out it doesn't, we'll skip the rest of the
|
||||||
|
|
|
@ -2501,6 +2501,35 @@ fn test() { (&S).foo()<|>; }
|
||||||
assert_eq!(t, "u128");
|
assert_eq!(t, "u128");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn method_resolution_trait_from_prelude() {
|
||||||
|
let (mut db, pos) = MockDatabase::with_position(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
struct S;
|
||||||
|
impl Clone for S {}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
S.clone()<|>;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- /lib.rs
|
||||||
|
#[prelude_import] use foo::*;
|
||||||
|
|
||||||
|
mod foo {
|
||||||
|
trait Clone {
|
||||||
|
fn clone(&self) -> Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
db.set_crate_graph_from_fixture(crate_graph! {
|
||||||
|
"main": ("/main.rs", ["other_crate"]),
|
||||||
|
"other_crate": ("/lib.rs", []),
|
||||||
|
});
|
||||||
|
assert_eq!("S", type_at_pos(&db, pos));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn method_resolution_where_clause_for_unknown_trait() {
|
fn method_resolution_where_clause_for_unknown_trait() {
|
||||||
// The blanket impl shouldn't apply because we can't even resolve UnknownTrait
|
// The blanket impl shouldn't apply because we can't even resolve UnknownTrait
|
||||||
|
|
Loading…
Add table
Reference in a new issue