From c947c15ce1ec02261803f10568e4659e9396109e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 24 Mar 2019 17:36:15 +0100 Subject: Basics for trait method resolution --- crates/ra_hir/src/code_model_api.rs | 13 +++++++ crates/ra_hir/src/db.rs | 4 +++ crates/ra_hir/src/lib.rs | 1 + crates/ra_hir/src/nameres.rs | 8 ++++- crates/ra_hir/src/resolve.rs | 17 ++++++++- crates/ra_hir/src/traits.rs | 52 +++++++++++++++++++++++++++ crates/ra_hir/src/ty/infer.rs | 3 +- crates/ra_hir/src/ty/method_resolution.rs | 60 +++++++++++++++++++++++-------- crates/ra_hir/src/ty/tests.rs | 12 +++---- crates/ra_syntax/src/ast/generated.rs | 6 +++- crates/ra_syntax/src/grammar.ron | 5 ++- 11 files changed, 156 insertions(+), 25 deletions(-) create mode 100644 crates/ra_hir/src/traits.rs (limited to 'crates') diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 5437133b8..88c13566c 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs @@ -17,6 +17,7 @@ use crate::{ impl_block::ImplBlock, resolve::Resolver, diagnostics::DiagnosticSink, + traits::{TraitItem, TraitData}, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -649,6 +650,18 @@ impl Trait { pub fn generic_params(&self, db: &impl DefDatabase) -> Arc { db.generic_params((*self).into()) } + + pub fn name(self, db: &impl DefDatabase) -> Option { + self.trait_data(db).name().clone() + } + + pub fn items(self, db: &impl DefDatabase) -> Vec { + self.trait_data(db).items().to_vec() + } + + pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc { + db.trait_data(self) + } } impl Docs for Trait { diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index d3908f8ac..dd0bf6e34 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -14,6 +14,7 @@ use crate::{ impl_block::{ModuleImplBlocks, ImplSourceMap}, generics::{GenericParams, GenericDef}, type_ref::TypeRef, + traits::TraitData, Trait }; #[salsa::query_group(DefDatabaseStorage)] @@ -27,6 +28,9 @@ pub trait DefDatabase: SourceDatabase + AsRef { #[salsa::invoke(crate::adt::EnumData::enum_data_query)] fn enum_data(&self, e: Enum) -> Arc; + #[salsa::invoke(crate::traits::TraitData::trait_data_query)] + fn trait_data(&self, t: Trait) -> Arc; + #[salsa::invoke(crate::ids::SourceFileItems::file_items_query)] fn file_items(&self, file_id: HirFileId) -> Arc; diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index ce54d7608..974ebd831 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -27,6 +27,7 @@ mod ids; mod name; mod nameres; mod adt; +mod traits; mod type_alias; mod type_ref; mod ty; diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 56ed872d5..c34aa4b50 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -62,7 +62,7 @@ use test_utils::tested_by; use crate::{ ModuleDef, Name, Crate, Module, - DefDatabase, Path, PathKind, HirFileId, + DefDatabase, Path, PathKind, HirFileId, Trait, ids::{SourceItemId, SourceFileItemId, MacroCallId}, diagnostics::DiagnosticSink, nameres::diagnostics::DefDiagnostic, @@ -139,6 +139,12 @@ impl ModuleScope { pub fn get(&self, name: &Name) -> Option<&Resolution> { self.items.get(name) } + pub fn traits<'a>(&'a self) -> impl Iterator + 'a { + self.items.values().filter_map(|r| match r.def.take_types() { + Some(ModuleDef::Trait(t)) => Some(t), + _ => None, + }) + } } #[derive(Debug, Clone, PartialEq, Eq, Default)] diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index f28154517..0f5031e76 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -11,7 +11,7 @@ use crate::{ generics::GenericParams, expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, impl_block::ImplBlock, - path::Path, + path::Path, Trait }; #[derive(Debug, Clone, Default)] @@ -175,6 +175,21 @@ impl Resolver { names } + pub(crate) fn traits_in_scope<'a>(&'a self) -> impl Iterator + 'a { + // FIXME prelude + self.scopes + .iter() + .rev() + .flat_map(|scope| { + match scope { + Scope::ModuleScope(m) => Some(m.crate_def_map[m.module_id].scope.traits()), + _ => None, + } + .into_iter() + }) + .flat_map(|i| i) + } + fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { self.scopes.iter().rev().find_map(|scope| match scope { Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs new file mode 100644 index 000000000..725bdd5cb --- /dev/null +++ b/crates/ra_hir/src/traits.rs @@ -0,0 +1,52 @@ +//! HIR for trait definitions. + +use std::sync::Arc; + +use ra_syntax::ast::{self, NameOwner}; + +use crate::{Function, Const, TypeAlias, Name, DefDatabase, Trait, ids::LocationCtx, name::AsName}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TraitData { + name: Option, + items: Vec, +} + +impl TraitData { + pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: Trait) -> Arc { + let (file_id, node) = tr.source(db); + let name = node.name().map(|n| n.as_name()); + let module = tr.module(db); + let ctx = LocationCtx::new(db, module, file_id); + let items = if let Some(item_list) = node.item_list() { + item_list + .impl_items() + .map(|item_node| match item_node.kind() { + ast::ImplItemKind::FnDef(it) => Function { id: ctx.to_def(it) }.into(), + ast::ImplItemKind::ConstDef(it) => Const { id: ctx.to_def(it) }.into(), + ast::ImplItemKind::TypeAliasDef(it) => TypeAlias { id: ctx.to_def(it) }.into(), + }) + .collect() + } else { + Vec::new() + }; + Arc::new(TraitData { name, items }) + } + + pub(crate) fn name(&self) -> &Option { + &self.name + } + + pub(crate) fn items(&self) -> &[TraitItem] { + &self.items + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum TraitItem { + Function(Function), + Const(Const), + TypeAlias(TypeAlias), + // Existential +} +impl_froms!(TraitItem: Function, Const, TypeAlias); diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 5fd602a9e..573115321 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -821,7 +821,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } Expr::MethodCall { receiver, args, method_name, generic_args } => { let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); - let resolved = receiver_ty.clone().lookup_method(self.db, method_name); + let resolved = + receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver); let (derefed_receiver_ty, method_ty, def_generics) = match resolved { Some((ty, func)) => { self.write_method_resolution(tgt_expr, func); diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index b1684acf9..708a435b4 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -11,7 +11,7 @@ use crate::{ ids::TraitId, impl_block::{ImplId, ImplBlock, ImplItem}, ty::{Ty, TypeCtor}, - nameres::CrateModuleId, + nameres::CrateModuleId, resolve::Resolver, traits::TraitItem }; @@ -73,18 +73,18 @@ impl CrateImplBlocks { let target_ty = impl_block.target_ty(db); - if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { - self.impls - .entry(target_ty_fp) - .or_insert_with(Vec::new) - .push((module.module_id, impl_id)); - } - if let Some(tr) = impl_block.target_trait(db) { self.impls_by_trait .entry(tr.id) .or_insert_with(Vec::new) .push((module.module_id, impl_id)); + } else { + if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { + self.impls + .entry(target_ty_fp) + .or_insert_with(Vec::new) + .push((module.module_id, impl_id)); + } } } @@ -120,20 +120,52 @@ fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option { } impl Ty { - // FIXME: cache this as a query? - // - if so, what signature? (TyFingerprint, Name)? - // - or maybe cache all names and def_ids of methods per fingerprint? /// Look up the method with the given name, returning the actual autoderefed /// receiver type (but without autoref applied yet). - pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> { - self.iterate_methods(db, |ty, f| { + pub fn lookup_method( + self, + db: &impl HirDatabase, + name: &Name, + resolver: &Resolver, + ) -> Option<(Ty, Function)> { + // FIXME: what has priority, an inherent method that needs autoderefs or a trait method? + let inherent_method = self.clone().iterate_methods(db, |ty, f| { let sig = f.signature(db); if sig.name() == name && sig.has_self_param() { Some((ty.clone(), f)) } else { None } - }) + }); + inherent_method.or_else(|| self.lookup_trait_method(db, name, resolver)) + } + + fn lookup_trait_method( + self, + db: &impl HirDatabase, + name: &Name, + resolver: &Resolver, + ) -> Option<(Ty, Function)> { + let mut candidates = Vec::new(); + for t in resolver.traits_in_scope() { + let data = t.trait_data(db); + for item in data.items() { + match item { + &TraitItem::Function(m) => { + let sig = m.signature(db); + if sig.name() == name && sig.has_self_param() { + candidates.push((t, m)); + } + } + _ => {} + } + } + } + // FIXME the implements check may result in other obligations or unifying variables? + candidates.retain(|(_t, _m)| /* self implements t */ true); + // FIXME what happens if there are still multiple potential candidates? + let (_chosen_trait, chosen_method) = candidates.first()?; + Some((self.clone(), *chosen_method)) } // This would be nicer if it just returned an iterator, but that runs into diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 3aedba243..971043266 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -1272,8 +1272,8 @@ fn test() { [241; 252) 'Struct::FOO': u32 [262; 263) 'y': u32 [266; 275) 'Enum::BAR': u32 -[285; 286) 'z': u32 -[289; 302) 'TraitTest::ID': u32"### +[285; 286) 'z': {unknown} +[289; 302) 'TraitTest::ID': {unknown}"### ); } @@ -1918,9 +1918,9 @@ fn test() { [110; 114) 'self': &{unknown} [170; 228) '{ ...i128 }': () [176; 178) 'S1': S1 -[176; 187) 'S1.method()': {unknown} +[176; 187) 'S1.method()': u32 [203; 205) 'S2': S2 -[203; 214) 'S2.method()': {unknown}"### +[203; 214) 'S2.method()': u32"### ); } @@ -1964,10 +1964,10 @@ mod bar_test { [169; 173) 'self': &{unknown} [300; 337) '{ ... }': () [310; 311) 'S': S -[310; 320) 'S.method()': {unknown} +[310; 320) 'S.method()': u32 [416; 454) '{ ... }': () [426; 427) 'S': S -[426; 436) 'S.method()': {unknown}"### +[426; 436) 'S.method()': i128"### ); } diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 54b72f8c5..47a37e4d1 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -4061,7 +4061,11 @@ impl ast::NameOwner for TraitDef {} impl ast::AttrsOwner for TraitDef {} impl ast::DocCommentsOwner for TraitDef {} impl ast::TypeParamsOwner for TraitDef {} -impl TraitDef {} +impl TraitDef { + pub fn item_list(&self) -> Option<&ItemList> { + super::child_opt(self) + } +} // TrueKw #[derive(Debug, PartialEq, Eq, Hash)] diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 4f8e19bd0..ad6d74162 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -292,7 +292,10 @@ Grammar( ], options: [["variant_list", "EnumVariantList"]] ), "EnumVariantList": ( collections: [["variants", "EnumVariant"]] ), "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner", "AttrsOwner"], options: ["Expr"] ), - "TraitDef": ( traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner"] ), + "TraitDef": ( + traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner"], + options: ["ItemList"] + ), "Module": ( traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner" ], options: [ "ItemList" ] -- cgit v1.2.3 From 0f7e4a7d2440e7e13a5cdf7e91f262426f0d0d18 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 24 Mar 2019 17:37:27 +0100 Subject: Implement a very naive implements check ... to make the infer_trait_method_simple test have the correct result. --- crates/ra_hir/src/db.rs | 5 ++++- crates/ra_hir/src/ty.rs | 23 ++++++++++++++++++---- crates/ra_hir/src/ty/method_resolution.rs | 32 +++++++++++++++++++++++++------ crates/ra_hir/src/ty/tests.rs | 2 +- 4 files changed, 50 insertions(+), 12 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index dd0bf6e34..143919cdc 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -14,7 +14,7 @@ use crate::{ impl_block::{ModuleImplBlocks, ImplSourceMap}, generics::{GenericParams, GenericDef}, type_ref::TypeRef, - traits::TraitData, Trait + traits::TraitData, Trait, ty::TraitRef }; #[salsa::query_group(DefDatabaseStorage)] @@ -102,6 +102,9 @@ pub trait HirDatabase: DefDatabase { #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] fn impls_in_crate(&self, krate: Crate) -> Arc; + + #[salsa::invoke(crate::ty::method_resolution::implements)] + fn implements(&self, trait_ref: TraitRef) -> bool; } #[test] diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 7d25ade47..d42c61e9d 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -14,7 +14,7 @@ pub(crate) mod display; use std::sync::Arc; use std::{fmt, mem}; -use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase}; +use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait}; pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig}; pub(crate) use infer::{infer, InferenceResult, InferTy}; @@ -91,7 +91,7 @@ pub enum TypeCtor { /// A nominal type with (maybe 0) type parameters. This might be a primitive /// type like `bool`, a struct, tuple, function pointer, reference or /// several other things. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct ApplicationTy { pub ctor: TypeCtor, pub parameters: Substs, @@ -103,7 +103,7 @@ pub struct ApplicationTy { /// the same thing (but in a different way). /// /// This should be cheap to clone. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub enum Ty { /// A nominal type with (maybe 0) type parameters. This might be a primitive /// type like `bool`, a struct, tuple, function pointer, reference or @@ -132,7 +132,7 @@ pub enum Ty { } /// A list of substitutions for generic parameters. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Substs(Arc<[Ty]>); impl Substs { @@ -169,6 +169,21 @@ impl Substs { } } +/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. +/// Name to be bikeshedded: TraitBound? TraitImplements? +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct TraitRef { + /// FIXME name? + trait_: Trait, + substs: Substs, +} + +impl TraitRef { + pub fn self_ty(&self) -> &Ty { + &self.substs.0[0] + } +} + /// A function signature as seen by type inference: Several parameter types and /// one return type. #[derive(Clone, PartialEq, Eq, Debug)] diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 708a435b4..146e8a02e 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -8,12 +8,12 @@ use rustc_hash::FxHashMap; use crate::{ HirDatabase, Module, Crate, Name, Function, Trait, - ids::TraitId, impl_block::{ImplId, ImplBlock, ImplItem}, ty::{Ty, TypeCtor}, nameres::CrateModuleId, resolve::Resolver, traits::TraitItem }; +use super::{ TraitRef, Substs}; /// This is used as a key for indexing impls. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -38,7 +38,7 @@ pub struct CrateImplBlocks { /// To make sense of the CrateModuleIds, we need the source root. krate: Crate, impls: FxHashMap>, - impls_by_trait: FxHashMap>, + impls_by_trait: FxHashMap>, } impl CrateImplBlocks { @@ -56,8 +56,7 @@ impl CrateImplBlocks { &'a self, tr: &Trait, ) -> impl Iterator + 'a { - let id = tr.id; - self.impls_by_trait.get(&id).into_iter().flat_map(|i| i.iter()).map( + self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map( move |(module_id, impl_id)| { let module = Module { krate: self.krate, module_id: *module_id }; ImplBlock::from_id(module, *impl_id) @@ -75,7 +74,7 @@ impl CrateImplBlocks { if let Some(tr) = impl_block.target_trait(db) { self.impls_by_trait - .entry(tr.id) + .entry(tr) .or_insert_with(Vec::new) .push((module.module_id, impl_id)); } else { @@ -109,6 +108,24 @@ impl CrateImplBlocks { } } +/// Rudimentary check whether an impl exists for a given type and trait; this +/// will actually be done by chalk. +pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> bool { + // FIXME use all trait impls in the whole crate graph + let krate = trait_ref.trait_.module(db).krate(db); + let krate = match krate { + Some(krate) => krate, + None => return false, + }; + let crate_impl_blocks = db.impls_in_crate(krate); + for impl_block in crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_) { + if &impl_block.target_ty(db) == trait_ref.self_ty() { + return true; + } + } + false +} + fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option { match ty { Ty::Apply(a_ty) => match a_ty.ctor { @@ -162,7 +179,10 @@ impl Ty { } } // FIXME the implements check may result in other obligations or unifying variables? - candidates.retain(|(_t, _m)| /* self implements t */ true); + candidates.retain(|(t, _m)| { + let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) }; + db.implements(trait_ref) + }); // FIXME what happens if there are still multiple potential candidates? let (_chosen_trait, chosen_method) = candidates.first()?; Some((self.clone(), *chosen_method)) diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 971043266..655f3c522 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -1920,7 +1920,7 @@ fn test() { [176; 178) 'S1': S1 [176; 187) 'S1.method()': u32 [203; 205) 'S2': S2 -[203; 214) 'S2.method()': u32"### +[203; 214) 'S2.method()': i128"### ); } -- cgit v1.2.3 From 99711c1863fc712dc14ca61809055b283415acbe Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 25 Mar 2019 21:24:20 +0100 Subject: Clean up comments / use nicer Iterator methods --- crates/ra_hir/src/resolve.rs | 2 +- crates/ra_hir/src/ty/method_resolution.rs | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 0f5031e76..2609585b1 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -187,7 +187,7 @@ impl Resolver { } .into_iter() }) - .flat_map(|i| i) + .flatten() } fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 146e8a02e..3ac8dc46b 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -118,12 +118,8 @@ pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> bool { None => return false, }; let crate_impl_blocks = db.impls_in_crate(krate); - for impl_block in crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_) { - if &impl_block.target_ty(db) == trait_ref.self_ty() { - return true; - } - } - false + let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_); + impl_blocks.any(|impl_block| &impl_block.target_ty(db) == trait_ref.self_ty()) } fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option { @@ -145,7 +141,7 @@ impl Ty { name: &Name, resolver: &Resolver, ) -> Option<(Ty, Function)> { - // FIXME: what has priority, an inherent method that needs autoderefs or a trait method? + // FIXME: trait methods should be used before autoderefs let inherent_method = self.clone().iterate_methods(db, |ty, f| { let sig = f.signature(db); if sig.name() == name && sig.has_self_param() { @@ -178,12 +174,21 @@ impl Ty { } } } - // FIXME the implements check may result in other obligations or unifying variables? + // FIXME: + // - we might not actually be able to determine fully that the type + // implements the trait here; it's enough if we (well, Chalk) determine + // that it's possible. + // - when the trait method is picked, we need to register an + // 'obligation' somewhere so that we later check that it's really + // implemented + // - both points go for additional requirements from where clauses as + // well (in fact, the 'implements' condition could just be considered a + // 'where Self: Trait' clause) candidates.retain(|(t, _m)| { let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) }; db.implements(trait_ref) }); - // FIXME what happens if there are still multiple potential candidates? + // FIXME if there's multiple candidates here, that's an ambiguity error let (_chosen_trait, chosen_method) = candidates.first()?; Some((self.clone(), *chosen_method)) } -- cgit v1.2.3