mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 14:21:44 +00:00
Start handling environment in trait resolution
I.e. if we are inside a function with some where clauses, we assume these where clauses hold.
This commit is contained in:
parent
638100dc8b
commit
b1b12072ed
6 changed files with 103 additions and 14 deletions
|
@ -27,10 +27,10 @@ use ra_prof::profile;
|
||||||
use test_utils::tested_by;
|
use test_utils::tested_by;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
autoderef, method_resolution, op, primitive,
|
autoderef, lower, method_resolution, op, primitive,
|
||||||
traits::{Guidance, Obligation, ProjectionPredicate, Solution},
|
traits::{Guidance, Obligation, ProjectionPredicate, Solution},
|
||||||
ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitRef, Ty, TypableDef,
|
ApplicationTy, CallableDef, Environment, InEnvironment, ProjectionTy, Substs, TraitRef, Ty,
|
||||||
TypeCtor,
|
TypableDef, TypeCtor,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
adt::VariantDef,
|
adt::VariantDef,
|
||||||
|
@ -166,6 +166,7 @@ struct InferenceContext<'a, D: HirDatabase> {
|
||||||
body: Arc<Body>,
|
body: Arc<Body>,
|
||||||
resolver: Resolver,
|
resolver: Resolver,
|
||||||
var_unification_table: InPlaceUnificationTable<TypeVarId>,
|
var_unification_table: InPlaceUnificationTable<TypeVarId>,
|
||||||
|
trait_env: Arc<Environment>,
|
||||||
obligations: Vec<Obligation>,
|
obligations: Vec<Obligation>,
|
||||||
method_resolutions: FxHashMap<ExprId, Function>,
|
method_resolutions: FxHashMap<ExprId, Function>,
|
||||||
field_resolutions: FxHashMap<ExprId, StructField>,
|
field_resolutions: FxHashMap<ExprId, StructField>,
|
||||||
|
@ -189,6 +190,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
var_unification_table: InPlaceUnificationTable::new(),
|
var_unification_table: InPlaceUnificationTable::new(),
|
||||||
obligations: Vec::default(),
|
obligations: Vec::default(),
|
||||||
return_ty: Ty::Unknown, // set in collect_fn_signature
|
return_ty: Ty::Unknown, // set in collect_fn_signature
|
||||||
|
trait_env: lower::trait_env(db, &resolver),
|
||||||
db,
|
db,
|
||||||
body,
|
body,
|
||||||
resolver,
|
resolver,
|
||||||
|
@ -331,8 +333,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
for obligation in obligations {
|
for obligation in obligations {
|
||||||
match &obligation {
|
match &obligation {
|
||||||
Obligation::Trait(tr) => {
|
Obligation::Trait(tr) => {
|
||||||
let env = Arc::new(super::Environment); // FIXME add environment
|
let in_env = InEnvironment::new(self.trait_env.clone(), tr.clone());
|
||||||
let in_env = InEnvironment::new(env, tr.clone());
|
|
||||||
let canonicalized = self.canonicalizer().canonicalize_trait_ref(in_env);
|
let canonicalized = self.canonicalizer().canonicalize_trait_ref(in_env);
|
||||||
let solution = self
|
let solution = self
|
||||||
.db
|
.db
|
||||||
|
|
|
@ -317,6 +317,18 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
|
||||||
Ty::from_hir(db, &resolver, type_ref)
|
Ty::from_hir(db, &resolver, type_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn trait_env(db: &impl HirDatabase, resolver: &Resolver) -> Arc<super::Environment> {
|
||||||
|
let predicates = resolver
|
||||||
|
.where_predicates_in_scope()
|
||||||
|
.map(|pred| {
|
||||||
|
TraitRef::for_where_predicate(db, &resolver, pred)
|
||||||
|
.map_or(GenericPredicate::Error, GenericPredicate::Implemented)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Arc::new(super::Environment { predicates })
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolve the where clause(s) of an item with generics.
|
/// Resolve the where clause(s) of an item with generics.
|
||||||
pub(crate) fn generic_predicates_query(
|
pub(crate) fn generic_predicates_query(
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::sync::Arc;
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use super::{autoderef, Canonical, Environment, InEnvironment, TraitRef};
|
use super::{autoderef, lower, Canonical, Environment, InEnvironment, TraitRef};
|
||||||
use crate::{
|
use crate::{
|
||||||
generics::HasGenericParams,
|
generics::HasGenericParams,
|
||||||
impl_block::{ImplBlock, ImplId, ImplItem},
|
impl_block::{ImplBlock, ImplId, ImplItem},
|
||||||
|
@ -198,6 +198,8 @@ 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()?;
|
||||||
|
// FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
|
||||||
|
let env = lower::trait_env(db, resolver);
|
||||||
'traits: for t in resolver.traits_in_scope(db) {
|
'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
|
||||||
|
@ -209,8 +211,7 @@ fn iterate_trait_method_candidates<T>(
|
||||||
let data = m.data(db);
|
let data = m.data(db);
|
||||||
if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
|
if name.map_or(true, |name| data.name() == name) && data.has_self_param() {
|
||||||
if !known_implemented {
|
if !known_implemented {
|
||||||
let env = Arc::new(super::Environment); // FIXME add environment
|
let trait_ref = canonical_trait_ref(db, env.clone(), t, ty.clone());
|
||||||
let trait_ref = canonical_trait_ref(db, env, t, ty.clone());
|
|
||||||
if db.implements(krate, trait_ref).is_none() {
|
if db.implements(krate, trait_ref).is_none() {
|
||||||
continue 'traits;
|
continue 'traits;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2950,6 +2950,66 @@ fn test(o: O<S>) {
|
||||||
assert_eq!(t, "&str");
|
assert_eq!(t, "&str");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generic_param_env_1() {
|
||||||
|
let t = type_at(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
trait Clone {}
|
||||||
|
trait Trait { fn foo(self) -> u128; }
|
||||||
|
struct S;
|
||||||
|
impl Clone for S {}
|
||||||
|
impl<T> Trait for T where T: Clone {}
|
||||||
|
fn test<T: Clone>(t: T) { t.foo()<|>; }
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
assert_eq!(t, "u128");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generic_param_env_1_not_met() {
|
||||||
|
let t = type_at(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
trait Clone {}
|
||||||
|
trait Trait { fn foo(self) -> u128; }
|
||||||
|
struct S;
|
||||||
|
impl Clone for S {}
|
||||||
|
impl<T> Trait for T where T: Clone {}
|
||||||
|
fn test<T>(t: T) { t.foo()<|>; }
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
assert_eq!(t, "{unknown}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generic_param_env_2() {
|
||||||
|
let t = type_at(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
trait Trait { fn foo(self) -> u128; }
|
||||||
|
struct S;
|
||||||
|
impl Trait for S {}
|
||||||
|
fn test<T: Trait>(t: T) { t.foo()<|>; }
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
assert_eq!(t, "u128");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generic_param_env_2_not_met() {
|
||||||
|
let t = type_at(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
trait Trait { fn foo(self) -> u128; }
|
||||||
|
struct S;
|
||||||
|
impl Trait for S {}
|
||||||
|
fn test<T>(t: T) { t.foo()<|>; }
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
assert_eq!(t, "{unknown}");
|
||||||
|
}
|
||||||
|
|
||||||
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
||||||
let file = db.parse(pos.file_id).ok().unwrap();
|
let file = db.parse(pos.file_id).ok().unwrap();
|
||||||
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
||||||
|
|
|
@ -72,11 +72,13 @@ fn solve(
|
||||||
/// fn foo<T: Default>(t: T) {}
|
/// fn foo<T: Default>(t: T) {}
|
||||||
/// ```
|
/// ```
|
||||||
/// we assume that `T: Default`.
|
/// we assume that `T: Default`.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Environment;
|
pub struct Environment {
|
||||||
|
pub predicates: Vec<GenericPredicate>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Something (usually a goal), along with an environment.
|
/// Something (usually a goal), along with an environment.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct InEnvironment<T> {
|
pub struct InEnvironment<T> {
|
||||||
pub environment: Arc<Environment>,
|
pub environment: Arc<Environment>,
|
||||||
pub value: T,
|
pub value: T,
|
||||||
|
|
|
@ -239,15 +239,28 @@ where
|
||||||
impl ToChalk for Arc<super::Environment> {
|
impl ToChalk for Arc<super::Environment> {
|
||||||
type Chalk = Arc<chalk_ir::Environment>;
|
type Chalk = Arc<chalk_ir::Environment>;
|
||||||
|
|
||||||
fn to_chalk(self, _db: &impl HirDatabase) -> Arc<chalk_ir::Environment> {
|
fn to_chalk(self, db: &impl HirDatabase) -> Arc<chalk_ir::Environment> {
|
||||||
chalk_ir::Environment::new()
|
let mut clauses = Vec::new();
|
||||||
|
for pred in &self.predicates {
|
||||||
|
if pred.is_error() {
|
||||||
|
// for env, we just ignore errors
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let GenericPredicate::Implemented(trait_ref) = pred {
|
||||||
|
if blacklisted_trait(db, trait_ref.trait_) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clauses.push(pred.clone().to_chalk(db).cast());
|
||||||
|
}
|
||||||
|
chalk_ir::Environment::new().add_clauses(clauses)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_chalk(
|
fn from_chalk(
|
||||||
_db: &impl HirDatabase,
|
_db: &impl HirDatabase,
|
||||||
_env: Arc<chalk_ir::Environment>,
|
_env: Arc<chalk_ir::Environment>,
|
||||||
) -> Arc<super::Environment> {
|
) -> Arc<super::Environment> {
|
||||||
Arc::new(super::Environment)
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue