mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 14:33:29 +00:00
Merge #1786
1786: Various minor trait improvements r=matklad a=flodiebold - lower bounds on trait definition, i.e. super traits - use super traits for associated types - use traits from where clauses and their super traits for method resolution - lower fn-like paths (i.e. `Fn(X, Y) -> Z`) - pass the environment to Chalk in the correct way to make elaboration work, i.e. inferring things like `T: Clone` from `T: Copy`. The clauses need to be wrapped in `FromEnv` clauses for that to work, which I didn't do before. - add some tests for closure inference already Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
commit
4a89a7c902
14 changed files with 394 additions and 40 deletions
|
@ -820,7 +820,52 @@ impl Trait {
|
||||||
self.trait_data(db).items().to_vec()
|
self.trait_data(db).items().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn associated_type_by_name(self, db: &impl DefDatabase, name: Name) -> Option<TypeAlias> {
|
fn direct_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> {
|
||||||
|
let resolver = self.resolver(db);
|
||||||
|
// returning the iterator directly doesn't easily work because of
|
||||||
|
// lifetime problems, but since there usually shouldn't be more than a
|
||||||
|
// few direct traits this should be fine (we could even use some kind of
|
||||||
|
// SmallVec if performance is a concern)
|
||||||
|
self.generic_params(db)
|
||||||
|
.where_predicates
|
||||||
|
.iter()
|
||||||
|
.filter_map(|pred| match &pred.type_ref {
|
||||||
|
TypeRef::Path(p) if p.as_ident() == Some(&crate::name::SELF_TYPE) => {
|
||||||
|
pred.bound.as_path()
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.filter_map(|path| {
|
||||||
|
match resolver.resolve_path_without_assoc_items(db, path).take_types() {
|
||||||
|
Some(crate::Resolution::Def(ModuleDef::Trait(t))) => Some(t),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the whole super trait hierarchy (including the
|
||||||
|
/// trait itself).
|
||||||
|
pub fn all_super_traits(self, db: &impl HirDatabase) -> Vec<Trait> {
|
||||||
|
// we need to take care a bit here to avoid infinite loops in case of cycles
|
||||||
|
// (i.e. if we have `trait A: B; trait B: A;`)
|
||||||
|
let mut result = vec![self];
|
||||||
|
let mut i = 0;
|
||||||
|
while i < result.len() {
|
||||||
|
let t = result[i];
|
||||||
|
// yeah this is quadratic, but trait hierarchies should be flat
|
||||||
|
// enough that this doesn't matter
|
||||||
|
for tt in t.direct_super_traits(db) {
|
||||||
|
if !result.contains(&tt) {
|
||||||
|
result.push(tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn associated_type_by_name(self, db: &impl DefDatabase, name: &Name) -> Option<TypeAlias> {
|
||||||
let trait_data = self.trait_data(db);
|
let trait_data = self.trait_data(db);
|
||||||
trait_data
|
trait_data
|
||||||
.items()
|
.items()
|
||||||
|
@ -829,7 +874,15 @@ impl Trait {
|
||||||
TraitItem::TypeAlias(t) => Some(*t),
|
TraitItem::TypeAlias(t) => Some(*t),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.find(|t| t.name(db) == name)
|
.find(|t| &t.name(db) == name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn associated_type_by_name_including_super_traits(
|
||||||
|
self,
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
name: &Name,
|
||||||
|
) -> Option<TypeAlias> {
|
||||||
|
self.all_super_traits(db).into_iter().find_map(|t| t.associated_type_by_name(db, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {
|
pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {
|
||||||
|
|
|
@ -87,11 +87,15 @@ impl GenericParams {
|
||||||
// traits get the Self type as an implicit first type parameter
|
// traits get the Self type as an implicit first type parameter
|
||||||
generics.params.push(GenericParam { idx: start, name: SELF_TYPE, default: None });
|
generics.params.push(GenericParam { idx: start, name: SELF_TYPE, default: None });
|
||||||
generics.fill(&it.source(db).ast, start + 1);
|
generics.fill(&it.source(db).ast, start + 1);
|
||||||
|
// add super traits as bounds on Self
|
||||||
|
// i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
|
||||||
|
let self_param = TypeRef::Path(SELF_TYPE.into());
|
||||||
|
generics.fill_bounds(&it.source(db).ast, self_param);
|
||||||
}
|
}
|
||||||
GenericDef::TypeAlias(it) => generics.fill(&it.source(db).ast, start),
|
GenericDef::TypeAlias(it) => generics.fill(&it.source(db).ast, start),
|
||||||
// Note that we don't add `Self` here: in `impl`s, `Self` is not a
|
// Note that we don't add `Self` here: in `impl`s, `Self` is not a
|
||||||
// type-parameter, but rather is a type-alias for impl's target
|
// type-parameter, but rather is a type-alias for impl's target
|
||||||
// type, so this is handled by the resovler.
|
// type, so this is handled by the resolver.
|
||||||
GenericDef::ImplBlock(it) => generics.fill(&it.source(db).ast, start),
|
GenericDef::ImplBlock(it) => generics.fill(&it.source(db).ast, start),
|
||||||
GenericDef::EnumVariant(_) => {}
|
GenericDef::EnumVariant(_) => {}
|
||||||
}
|
}
|
||||||
|
@ -108,6 +112,14 @@ impl GenericParams {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fill_bounds(&mut self, node: &impl ast::TypeBoundsOwner, type_ref: TypeRef) {
|
||||||
|
for bound in
|
||||||
|
node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
|
||||||
|
{
|
||||||
|
self.add_where_predicate_from_bound(bound, type_ref.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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_or_else(Name::missing, |it| it.as_name());
|
let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
|
||||||
|
@ -117,13 +129,7 @@ impl GenericParams {
|
||||||
self.params.push(param);
|
self.params.push(param);
|
||||||
|
|
||||||
let type_ref = TypeRef::Path(name.into());
|
let type_ref = TypeRef::Path(name.into());
|
||||||
for bound in type_param
|
self.fill_bounds(&type_param, type_ref);
|
||||||
.type_bound_list()
|
|
||||||
.iter()
|
|
||||||
.flat_map(|type_bound_list| type_bound_list.bounds())
|
|
||||||
{
|
|
||||||
self.add_where_predicate_from_bound(bound, type_ref.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,11 +38,6 @@ impl Name {
|
||||||
Name::new(idx.to_string().into())
|
Name::new(idx.to_string().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needed for Deref
|
|
||||||
pub(crate) fn target() -> Name {
|
|
||||||
Name::new("Target".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
// There's should be no way to extract a string out of `Name`: `Name` in the
|
// There's should be no way to extract a string out of `Name`: `Name` in the
|
||||||
// future, `Name` will include hygiene information, and you can't encode
|
// future, `Name` will include hygiene information, and you can't encode
|
||||||
// hygiene into a String.
|
// hygiene into a String.
|
||||||
|
@ -123,6 +118,7 @@ pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6,
|
||||||
pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result"));
|
pub(crate) const RESULT_MOD: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result"));
|
||||||
pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result"));
|
pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result"));
|
||||||
pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output"));
|
pub(crate) const OUTPUT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output"));
|
||||||
|
pub(crate) const TARGET: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target"));
|
||||||
|
|
||||||
fn resolve_name(text: &SmolStr) -> SmolStr {
|
fn resolve_name(text: &SmolStr) -> SmolStr {
|
||||||
let raw_start = "r#";
|
let raw_start = "r#";
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
ast::{self, NameOwner},
|
ast::{self, NameOwner, TypeAscriptionOwner},
|
||||||
AstNode,
|
AstNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{type_ref::TypeRef, AsName, Name};
|
use crate::{name, type_ref::TypeRef, AsName, Name};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Path {
|
pub struct Path {
|
||||||
|
@ -76,8 +76,16 @@ impl Path {
|
||||||
|
|
||||||
match segment.kind()? {
|
match segment.kind()? {
|
||||||
ast::PathSegmentKind::Name(name) => {
|
ast::PathSegmentKind::Name(name) => {
|
||||||
let args =
|
let args = segment
|
||||||
segment.type_arg_list().and_then(GenericArgs::from_ast).map(Arc::new);
|
.type_arg_list()
|
||||||
|
.and_then(GenericArgs::from_ast)
|
||||||
|
.or_else(|| {
|
||||||
|
GenericArgs::from_fn_like_path_ast(
|
||||||
|
segment.param_list(),
|
||||||
|
segment.ret_type(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map(Arc::new);
|
||||||
let segment = PathSegment { name: name.as_name(), args_and_bindings: args };
|
let segment = PathSegment { name: name.as_name(), args_and_bindings: args };
|
||||||
segments.push(segment);
|
segments.push(segment);
|
||||||
}
|
}
|
||||||
|
@ -187,6 +195,34 @@ impl GenericArgs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
|
||||||
|
/// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
|
||||||
|
pub(crate) fn from_fn_like_path_ast(
|
||||||
|
params: Option<ast::ParamList>,
|
||||||
|
ret_type: Option<ast::RetType>,
|
||||||
|
) -> Option<GenericArgs> {
|
||||||
|
let mut args = Vec::new();
|
||||||
|
let mut bindings = Vec::new();
|
||||||
|
if let Some(params) = params {
|
||||||
|
let mut param_types = Vec::new();
|
||||||
|
for param in params.params() {
|
||||||
|
let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
|
||||||
|
param_types.push(type_ref);
|
||||||
|
}
|
||||||
|
let arg = GenericArg::Type(TypeRef::Tuple(param_types));
|
||||||
|
args.push(arg);
|
||||||
|
}
|
||||||
|
if let Some(ret_type) = ret_type {
|
||||||
|
let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
|
||||||
|
bindings.push((name::OUTPUT, type_ref))
|
||||||
|
}
|
||||||
|
if args.is_empty() && bindings.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(GenericArgs { args, has_self_type: false, bindings })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn empty() -> GenericArgs {
|
pub(crate) fn empty() -> GenericArgs {
|
||||||
GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
|
GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::iter::successors;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
use super::{traits::Solution, Canonical, Ty, TypeWalk};
|
use super::{traits::Solution, Canonical, Ty, TypeWalk};
|
||||||
use crate::{HasGenericParams, HirDatabase, Name, Resolver};
|
use crate::{name, HasGenericParams, HirDatabase, Resolver};
|
||||||
|
|
||||||
const AUTODEREF_RECURSION_LIMIT: usize = 10;
|
const AUTODEREF_RECURSION_LIMIT: usize = 10;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ fn deref_by_trait(
|
||||||
crate::lang_item::LangItemTarget::Trait(t) => t,
|
crate::lang_item::LangItemTarget::Trait(t) => t,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let target = deref_trait.associated_type_by_name(db, Name::target())?;
|
let target = deref_trait.associated_type_by_name(db, &name::TARGET)?;
|
||||||
|
|
||||||
if target.generic_params(db).count_params_including_parent() != 1 {
|
if target.generic_params(db).count_params_including_parent() != 1 {
|
||||||
// the Target type + Deref trait should only have one generic parameter,
|
// the Target type + Deref trait should only have one generic parameter,
|
||||||
|
|
|
@ -1453,7 +1453,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() {
|
match self.resolver.resolve_path_segments(self.db, &into_iter_path).into_fully_resolved() {
|
||||||
PerNs { types: Some(Def(Trait(trait_))), .. } => {
|
PerNs { types: Some(Def(Trait(trait_))), .. } => {
|
||||||
Some(trait_.associated_type_by_name(self.db, name::ITEM)?)
|
Some(trait_.associated_type_by_name(self.db, &name::ITEM)?)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -1471,7 +1471,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
match self.resolver.resolve_path_segments(self.db, &ops_try_path).into_fully_resolved() {
|
match self.resolver.resolve_path_segments(self.db, &ops_try_path).into_fully_resolved() {
|
||||||
PerNs { types: Some(Def(Trait(trait_))), .. } => {
|
PerNs { types: Some(Def(Trait(trait_))), .. } => {
|
||||||
Some(trait_.associated_type_by_name(self.db, name::OK)?)
|
Some(trait_.associated_type_by_name(self.db, &name::OK)?)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -1493,7 +1493,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
.into_fully_resolved()
|
.into_fully_resolved()
|
||||||
{
|
{
|
||||||
PerNs { types: Some(Def(Trait(trait_))), .. } => {
|
PerNs { types: Some(Def(Trait(trait_))), .. } => {
|
||||||
Some(trait_.associated_type_by_name(self.db, name::OUTPUT)?)
|
Some(trait_.associated_type_by_name(self.db, &name::OUTPUT)?)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,8 +132,10 @@ impl Ty {
|
||||||
if let Some(remaining_index) = remaining_index {
|
if let Some(remaining_index) = remaining_index {
|
||||||
if remaining_index == path.segments.len() - 1 {
|
if remaining_index == path.segments.len() - 1 {
|
||||||
let segment = &path.segments[remaining_index];
|
let segment = &path.segments[remaining_index];
|
||||||
let associated_ty =
|
let associated_ty = match trait_ref
|
||||||
match trait_ref.trait_.associated_type_by_name(db, segment.name.clone()) {
|
.trait_
|
||||||
|
.associated_type_by_name_including_super_traits(db, &segment.name)
|
||||||
|
{
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
None => {
|
None => {
|
||||||
// associated type not found
|
// associated type not found
|
||||||
|
@ -387,7 +389,8 @@ fn assoc_type_bindings_from_type_bound<'a>(
|
||||||
.flat_map(|segment| segment.args_and_bindings.iter())
|
.flat_map(|segment| segment.args_and_bindings.iter())
|
||||||
.flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
|
.flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
|
||||||
.map(move |(name, type_ref)| {
|
.map(move |(name, type_ref)| {
|
||||||
let associated_ty = match trait_ref.trait_.associated_type_by_name(db, name.clone()) {
|
let associated_ty =
|
||||||
|
match trait_ref.trait_.associated_type_by_name_including_super_traits(db, &name) {
|
||||||
None => return GenericPredicate::Error,
|
None => return GenericPredicate::Error,
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
};
|
};
|
||||||
|
|
|
@ -212,7 +212,13 @@ fn iterate_trait_method_candidates<T>(
|
||||||
// FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
|
// 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);
|
let env = lower::trait_env(db, resolver);
|
||||||
// if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
|
// if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
|
||||||
let traits = ty.value.inherent_trait().into_iter().chain(resolver.traits_in_scope(db));
|
let inherent_trait = ty.value.inherent_trait().into_iter();
|
||||||
|
// if we have `T: Trait` in the param env, the trait doesn't need to be in scope
|
||||||
|
let traits_from_env = env
|
||||||
|
.trait_predicates_for_self_ty(&ty.value)
|
||||||
|
.map(|tr| tr.trait_)
|
||||||
|
.flat_map(|t| t.all_super_traits(db));
|
||||||
|
let traits = inherent_trait.chain(traits_from_env).chain(resolver.traits_in_scope(db));
|
||||||
'traits: for t in traits {
|
'traits: for t in traits {
|
||||||
let data = t.trait_data(db);
|
let data = t.trait_data(db);
|
||||||
|
|
||||||
|
|
|
@ -3643,6 +3643,231 @@ fn test<T: Trait1<Type = u32>>(x: T) {
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn where_clause_trait_in_scope_for_method_resolution() {
|
||||||
|
let t = type_at(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
mod foo {
|
||||||
|
trait Trait {
|
||||||
|
fn foo(&self) -> u32 {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test<T: foo::Trait>(x: T) {
|
||||||
|
x.foo()<|>;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
assert_eq!(t, "u32");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn super_trait_method_resolution() {
|
||||||
|
assert_snapshot!(
|
||||||
|
infer(r#"
|
||||||
|
mod foo {
|
||||||
|
trait SuperTrait {
|
||||||
|
fn foo(&self) -> u32 {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trait Trait1: foo::SuperTrait {}
|
||||||
|
trait Trait2 where Self: foo::SuperTrait {}
|
||||||
|
|
||||||
|
fn test<T: Trait1, U: Trait2>(x: T, y: U) {
|
||||||
|
x.foo();
|
||||||
|
y.foo();
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
[50; 54) 'self': &Self
|
||||||
|
[63; 65) '{}': ()
|
||||||
|
[182; 183) 'x': T
|
||||||
|
[188; 189) 'y': U
|
||||||
|
[194; 223) '{ ...o(); }': ()
|
||||||
|
[200; 201) 'x': T
|
||||||
|
[200; 207) 'x.foo()': u32
|
||||||
|
[213; 214) 'y': U
|
||||||
|
[213; 220) 'y.foo()': u32
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn super_trait_cycle() {
|
||||||
|
// This just needs to not crash
|
||||||
|
assert_snapshot!(
|
||||||
|
infer(r#"
|
||||||
|
trait A: B {}
|
||||||
|
trait B: A {}
|
||||||
|
|
||||||
|
fn test<T: A>(x: T) {
|
||||||
|
x.foo();
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
[44; 45) 'x': T
|
||||||
|
[50; 66) '{ ...o(); }': ()
|
||||||
|
[56; 57) 'x': T
|
||||||
|
[56; 63) 'x.foo()': {unknown}
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn super_trait_assoc_type_bounds() {
|
||||||
|
assert_snapshot!(
|
||||||
|
infer(r#"
|
||||||
|
trait SuperTrait { type Type; }
|
||||||
|
trait Trait where Self: SuperTrait {}
|
||||||
|
|
||||||
|
fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
|
||||||
|
fn set<T: Trait<Type = u64>>(t: T) -> T {t}
|
||||||
|
|
||||||
|
struct S<T>;
|
||||||
|
impl<T> SuperTrait for S<T> { type Type = T; }
|
||||||
|
impl<T> Trait for S<T> {}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
get2(set(S));
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
[103; 104) 't': T
|
||||||
|
[114; 116) '{}': ()
|
||||||
|
[146; 147) 't': T
|
||||||
|
[157; 160) '{t}': T
|
||||||
|
[158; 159) 't': T
|
||||||
|
[259; 280) '{ ...S)); }': ()
|
||||||
|
[265; 269) 'get2': fn get2<u64, S<u64>>(T) -> U
|
||||||
|
[265; 277) 'get2(set(S))': u64
|
||||||
|
[270; 273) 'set': fn set<S<u64>>(T) -> T
|
||||||
|
[270; 276) 'set(S)': S<u64>
|
||||||
|
[274; 275) 'S': S<u64>
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fn_trait() {
|
||||||
|
assert_snapshot!(
|
||||||
|
infer(r#"
|
||||||
|
trait FnOnce<Args> {
|
||||||
|
type Output;
|
||||||
|
|
||||||
|
fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
|
||||||
|
f.call_once((1, 2));
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
[57; 61) 'self': Self
|
||||||
|
[63; 67) 'args': Args
|
||||||
|
[150; 151) 'f': F
|
||||||
|
[156; 184) '{ ...2)); }': ()
|
||||||
|
[162; 163) 'f': F
|
||||||
|
[162; 181) 'f.call...1, 2))': {unknown}
|
||||||
|
[174; 180) '(1, 2)': (u32, u64)
|
||||||
|
[175; 176) '1': u32
|
||||||
|
[178; 179) '2': u64
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn closure_1() {
|
||||||
|
assert_snapshot!(
|
||||||
|
infer(r#"
|
||||||
|
trait FnOnce<Args> {
|
||||||
|
type Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Option<T> { Some(T), None }
|
||||||
|
impl<T> Option<T> {
|
||||||
|
fn map<U, F: FnOnce(T) -> U>(self, f: F) -> U {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let x = Option::Some(1i32);
|
||||||
|
x.map(|v| v + 1);
|
||||||
|
x.map(|_v| 1u64);
|
||||||
|
let y: Option<i64> = x.map(|_v| 1);
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
[128; 132) 'self': Option<T>
|
||||||
|
[134; 135) 'f': F
|
||||||
|
[145; 147) '{}': ()
|
||||||
|
[161; 280) '{ ... 1); }': ()
|
||||||
|
[171; 172) 'x': Option<i32>
|
||||||
|
[175; 187) 'Option::Some': Some<i32>(T) -> Option<T>
|
||||||
|
[175; 193) 'Option...(1i32)': Option<i32>
|
||||||
|
[188; 192) '1i32': i32
|
||||||
|
[199; 200) 'x': Option<i32>
|
||||||
|
[199; 215) 'x.map(...v + 1)': {unknown}
|
||||||
|
[205; 214) '|v| v + 1': {unknown}
|
||||||
|
[206; 207) 'v': {unknown}
|
||||||
|
[209; 210) 'v': {unknown}
|
||||||
|
[209; 214) 'v + 1': i32
|
||||||
|
[213; 214) '1': i32
|
||||||
|
[221; 222) 'x': Option<i32>
|
||||||
|
[221; 237) 'x.map(... 1u64)': {unknown}
|
||||||
|
[227; 236) '|_v| 1u64': {unknown}
|
||||||
|
[228; 230) '_v': {unknown}
|
||||||
|
[232; 236) '1u64': u64
|
||||||
|
[247; 248) 'y': Option<i64>
|
||||||
|
[264; 265) 'x': Option<i32>
|
||||||
|
[264; 277) 'x.map(|_v| 1)': Option<i64>
|
||||||
|
[270; 276) '|_v| 1': {unknown}
|
||||||
|
[271; 273) '_v': {unknown}
|
||||||
|
[275; 276) '1': i32
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn closure_2() {
|
||||||
|
assert_snapshot!(
|
||||||
|
infer(r#"
|
||||||
|
trait FnOnce<Args> {
|
||||||
|
type Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test<F: FnOnce(u32) -> u64>(f: F) {
|
||||||
|
f(1);
|
||||||
|
let g = |v| v + 1;
|
||||||
|
g(1u64);
|
||||||
|
let h = |v| 1u128 + v;
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
[73; 74) 'f': F
|
||||||
|
[79; 155) '{ ...+ v; }': ()
|
||||||
|
[85; 86) 'f': F
|
||||||
|
[85; 89) 'f(1)': {unknown}
|
||||||
|
[87; 88) '1': i32
|
||||||
|
[99; 100) 'g': {unknown}
|
||||||
|
[103; 112) '|v| v + 1': {unknown}
|
||||||
|
[104; 105) 'v': {unknown}
|
||||||
|
[107; 108) 'v': {unknown}
|
||||||
|
[107; 112) 'v + 1': i32
|
||||||
|
[111; 112) '1': i32
|
||||||
|
[118; 119) 'g': {unknown}
|
||||||
|
[118; 125) 'g(1u64)': {unknown}
|
||||||
|
[120; 124) '1u64': u64
|
||||||
|
[135; 136) 'h': {unknown}
|
||||||
|
[139; 152) '|v| 1u128 + v': {unknown}
|
||||||
|
[140; 141) 'v': u128
|
||||||
|
[143; 148) '1u128': u128
|
||||||
|
[143; 152) '1u128 + v': u128
|
||||||
|
[151; 152) 'v': u128
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
|
|
@ -96,6 +96,21 @@ pub struct TraitEnvironment {
|
||||||
pub predicates: Vec<GenericPredicate>,
|
pub predicates: Vec<GenericPredicate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TraitEnvironment {
|
||||||
|
/// Returns trait refs with the given self type which are supposed to hold
|
||||||
|
/// in this trait env. E.g. if we are in `foo<T: SomeTrait>()`, this will
|
||||||
|
/// find that `T: SomeTrait` if we call it for `T`.
|
||||||
|
pub(crate) fn trait_predicates_for_self_ty<'a>(
|
||||||
|
&'a self,
|
||||||
|
ty: &'a Ty,
|
||||||
|
) -> impl Iterator<Item = &'a TraitRef> + 'a {
|
||||||
|
self.predicates.iter().filter_map(move |pred| match pred {
|
||||||
|
GenericPredicate::Implemented(tr) if tr.self_ty() == ty => Some(tr),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Something (usually a goal), along with an environment.
|
/// Something (usually a goal), along with an environment.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct InEnvironment<T> {
|
pub struct InEnvironment<T> {
|
||||||
|
|
|
@ -314,7 +314,8 @@ impl ToChalk for Arc<super::TraitEnvironment> {
|
||||||
// for env, we just ignore errors
|
// for env, we just ignore errors
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
clauses.push(pred.clone().to_chalk(db).cast());
|
let program_clause: chalk_ir::ProgramClause = pred.clone().to_chalk(db).cast();
|
||||||
|
clauses.push(program_clause.into_from_env_clause());
|
||||||
}
|
}
|
||||||
chalk_ir::Environment::new().add_clauses(clauses)
|
chalk_ir::Environment::new().add_clauses(clauses)
|
||||||
}
|
}
|
||||||
|
@ -636,7 +637,7 @@ pub(crate) fn impl_datum_query(
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.filter_map(|t| {
|
.filter_map(|t| {
|
||||||
let assoc_ty = trait_.associated_type_by_name(db, t.name(db))?;
|
let assoc_ty = trait_.associated_type_by_name(db, &t.name(db))?;
|
||||||
let ty = db.type_for_def(t.into(), crate::Namespace::Types).subst(&bound_vars);
|
let ty = db.type_for_def(t.into(), crate::Namespace::Types).subst(&bound_vars);
|
||||||
Some(chalk_rust_ir::AssociatedTyValue {
|
Some(chalk_rust_ir::AssociatedTyValue {
|
||||||
impl_id,
|
impl_id,
|
||||||
|
|
|
@ -150,4 +150,11 @@ impl TypeBound {
|
||||||
ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error,
|
ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_path(&self) -> Option<&Path> {
|
||||||
|
match self {
|
||||||
|
TypeBound::Path(p) => Some(p),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2312,6 +2312,12 @@ impl PathSegment {
|
||||||
pub fn type_arg_list(&self) -> Option<TypeArgList> {
|
pub fn type_arg_list(&self) -> Option<TypeArgList> {
|
||||||
AstChildren::new(&self.syntax).next()
|
AstChildren::new(&self.syntax).next()
|
||||||
}
|
}
|
||||||
|
pub fn param_list(&self) -> Option<ParamList> {
|
||||||
|
AstChildren::new(&self.syntax).next()
|
||||||
|
}
|
||||||
|
pub fn ret_type(&self) -> Option<RetType> {
|
||||||
|
AstChildren::new(&self.syntax).next()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct PathType {
|
pub struct PathType {
|
||||||
|
|
|
@ -684,7 +684,7 @@ Grammar(
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
"PathSegment": (
|
"PathSegment": (
|
||||||
options: [ "NameRef", "TypeArgList" ]
|
options: [ "NameRef", "TypeArgList", "ParamList", "RetType" ]
|
||||||
),
|
),
|
||||||
"TypeArgList": (collections: [
|
"TypeArgList": (collections: [
|
||||||
("type_args", "TypeArg"),
|
("type_args", "TypeArg"),
|
||||||
|
|
Loading…
Reference in a new issue