From 8c2670026a4c864a67a06bab654e203ed068f021 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 28 Apr 2020 00:40:32 +0200 Subject: Complete assoc. items on type parameters --- crates/ra_hir_ty/src/lib.rs | 3 +- crates/ra_hir_ty/src/lower.rs | 144 ++++++++++++++++++++++++++---------------- 2 files changed, 90 insertions(+), 57 deletions(-) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index a8ef32ec5..341a18683 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -66,7 +66,8 @@ pub use autoderef::autoderef; pub use infer::{InferTy, InferenceResult}; pub use lower::CallableDef; pub use lower::{ - callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId, + associated_types, callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, + ValueTyDefId, }; pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index a6f893037..67e5c1ccd 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -17,9 +17,9 @@ use hir_def::{ path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, type_ref::{TypeBound, TypeRef}, - AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, - ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, - VariantId, + AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, + HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, + UnionId, VariantId, }; use ra_arena::map::ArenaMap; use ra_db::CrateId; @@ -34,6 +34,7 @@ use crate::{ Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, }; +use hir_expand::name::Name; #[derive(Debug)] pub struct TyLoweringContext<'a> { @@ -383,61 +384,37 @@ impl Ty { res: Option, segment: PathSegment<'_>, ) -> Ty { - let traits_from_env: Vec<_> = match res { - Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) { - None => return Ty::Unknown, - Some(trait_ref) => vec![trait_ref.value], - }, - Some(TypeNs::GenericParam(param_id)) => { - let predicates = ctx.db.generic_predicates_for_param(param_id); - let mut traits_: Vec<_> = predicates - .iter() - .filter_map(|pred| match &pred.value { - GenericPredicate::Implemented(tr) => Some(tr.clone()), - _ => None, - }) - .collect(); - // Handle `Self::Type` referring to own associated type in trait definitions - if let GenericDefId::TraitId(trait_id) = param_id.parent { - let generics = generics(ctx.db.upcast(), trait_id.into()); - if generics.params.types[param_id.local_id].provenance - == TypeParamProvenance::TraitSelf - { - let trait_ref = TraitRef { - trait_: trait_id, - substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST), - }; - traits_.push(trait_ref); - } + if let Some(res) = res { + let ty = associated_types(ctx.db, res, move |name, t, associated_ty| { + if name == segment.name { + let substs = match ctx.type_param_mode { + TypeParamLoweringMode::Placeholder => { + // if we're lowering to placeholders, we have to put + // them in now + let s = Substs::type_params( + ctx.db, + ctx.resolver + .generic_def() + .expect("there should be generics if there's a generic param"), + ); + t.substs.clone().subst_bound_vars(&s) + } + TypeParamLoweringMode::Variable => t.substs.clone(), + }; + // FIXME handle type parameters on the segment + return Some(Ty::Projection(ProjectionTy { + associated_ty, + parameters: substs, + })); } - traits_ - } - _ => return Ty::Unknown, - }; - let traits = traits_from_env.into_iter().flat_map(|t| all_super_trait_refs(ctx.db, t)); - for t in traits { - if let Some(associated_ty) = - ctx.db.trait_data(t.trait_).associated_type_by_name(&segment.name) - { - let substs = match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => { - // if we're lowering to placeholders, we have to put - // them in now - let s = Substs::type_params( - ctx.db, - ctx.resolver - .generic_def() - .expect("there should be generics if there's a generic param"), - ); - t.substs.subst_bound_vars(&s) - } - TypeParamLoweringMode::Variable => t.substs, - }; - // FIXME handle (forbid) type parameters on the segment - return Ty::Projection(ProjectionTy { associated_ty, parameters: substs }); - } + + None + }); + + ty.unwrap_or(Ty::Unknown) + } else { + Ty::Unknown } - Ty::Unknown } fn from_hir_path_inner( @@ -694,6 +671,61 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { } } +pub fn associated_types( + db: &dyn HirDatabase, + res: TypeNs, + mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option, +) -> Option { + let traits_from_env: Vec<_> = match res { + TypeNs::SelfType(impl_id) => match db.impl_trait(impl_id) { + None => vec![], + Some(trait_ref) => vec![trait_ref.value], + }, + TypeNs::GenericParam(param_id) => { + let predicates = db.generic_predicates_for_param(param_id); + let mut traits_: Vec<_> = predicates + .iter() + .filter_map(|pred| match &pred.value { + GenericPredicate::Implemented(tr) => Some(tr.clone()), + _ => None, + }) + .collect(); + // Handle `Self::Type` referring to own associated type in trait definitions + if let GenericDefId::TraitId(trait_id) = param_id.parent { + let generics = generics(db.upcast(), trait_id.into()); + if generics.params.types[param_id.local_id].provenance + == TypeParamProvenance::TraitSelf + { + let trait_ref = TraitRef { + trait_: trait_id, + substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST), + }; + traits_.push(trait_ref); + } + } + traits_ + } + _ => vec![], + }; + + for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) { + let data = db.trait_data(t.trait_); + + for (name, assoc_id) in &data.items { + match assoc_id { + AssocItemId::TypeAliasId(alias) => { + if let Some(result) = cb(name, &t, *alias) { + return Some(result); + } + } + AssocItemId::FunctionId(_) | AssocItemId::ConstId(_) => {} + } + } + } + + None +} + /// Build the type of all specific fields of a struct or enum variant. pub(crate) fn field_types_query( db: &dyn HirDatabase, -- cgit v1.2.3 From 3cb73da9499938e6f09736e4b6fba33474c3ce9c Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 30 Apr 2020 00:03:36 +0200 Subject: Rename to associated_type_shorthand_candidates --- crates/ra_hir_ty/src/lib.rs | 4 ++-- crates/ra_hir_ty/src/lower.rs | 51 ++++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 27 deletions(-) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 341a18683..a6f56c661 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -66,8 +66,8 @@ pub use autoderef::autoderef; pub use infer::{InferTy, InferenceResult}; pub use lower::CallableDef; pub use lower::{ - associated_types, callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, - ValueTyDefId, + associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId, + TyLoweringContext, ValueTyDefId, }; pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 67e5c1ccd..9ad6dbe07 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs @@ -385,31 +385,32 @@ impl Ty { segment: PathSegment<'_>, ) -> Ty { if let Some(res) = res { - let ty = associated_types(ctx.db, res, move |name, t, associated_ty| { - if name == segment.name { - let substs = match ctx.type_param_mode { - TypeParamLoweringMode::Placeholder => { - // if we're lowering to placeholders, we have to put - // them in now - let s = Substs::type_params( - ctx.db, - ctx.resolver - .generic_def() - .expect("there should be generics if there's a generic param"), - ); - t.substs.clone().subst_bound_vars(&s) - } - TypeParamLoweringMode::Variable => t.substs.clone(), - }; - // FIXME handle type parameters on the segment - return Some(Ty::Projection(ProjectionTy { - associated_ty, - parameters: substs, - })); - } + let ty = + associated_type_shorthand_candidates(ctx.db, res, move |name, t, associated_ty| { + if name == segment.name { + let substs = match ctx.type_param_mode { + TypeParamLoweringMode::Placeholder => { + // if we're lowering to placeholders, we have to put + // them in now + let s = Substs::type_params( + ctx.db, + ctx.resolver.generic_def().expect( + "there should be generics if there's a generic param", + ), + ); + t.substs.clone().subst_bound_vars(&s) + } + TypeParamLoweringMode::Variable => t.substs.clone(), + }; + // FIXME handle type parameters on the segment + return Some(Ty::Projection(ProjectionTy { + associated_ty, + parameters: substs, + })); + } - None - }); + None + }); ty.unwrap_or(Ty::Unknown) } else { @@ -671,7 +672,7 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig { } } -pub fn associated_types( +pub fn associated_type_shorthand_candidates( db: &dyn HirDatabase, res: TypeNs, mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option, -- cgit v1.2.3 From 14126349be47ee28e7feb1ebb2dd1f0392537e56 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 30 Apr 2020 22:44:42 +0200 Subject: Kill more zombies --- crates/ra_hir_ty/src/infer/expr.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 83f946eee..efc60986b 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -73,11 +73,6 @@ impl<'a> InferenceContext<'a> { self.coerce_merge_branch(&then_ty, &else_ty) } Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), - Expr::TryBlock { body } => { - let _inner = self.infer_expr(*body, expected); - // FIXME should be std::result::Result<{inner}, _> - Ty::Unknown - } Expr::Loop { body } => { self.infer_expr(*body, &Expectation::has_type(Ty::unit())); // FIXME handle break with value -- cgit v1.2.3 From e4267967a8ee3b35d902931cecf06bb4e19f86c5 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Fri, 1 May 2020 11:23:03 +0800 Subject: Support local_inner_macros --- crates/ra_hir_ty/src/tests/macros.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 5ddecbdc6..70e17bc94 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -387,6 +387,32 @@ fn main() { ); } +#[test] +fn infer_local_inner_macros() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:foo +fn test() { + let x = foo::foo!(1); + x<|>; +} + +//- /lib.rs crate:foo +#[macro_export(local_inner_macros)] +macro_rules! foo { + (1) => { bar!() }; +} + +#[macro_export] +macro_rules! bar { + () => { 42 } +} + +"#, + ); + assert_eq!("i32", type_at_pos(&db, pos)); +} + #[test] fn infer_builtin_macros_line() { assert_snapshot!( -- cgit v1.2.3 From 1635d22a355b08309661e3d54d22c6bc2b53e5e1 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Thu, 30 Apr 2020 18:12:52 +0800 Subject: Add test --- crates/ra_hir_ty/src/tests/macros.rs | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 5ddecbdc6..1f796876d 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -338,6 +338,46 @@ pub fn baz() -> usize { 31usize } assert_eq!("(i32, usize)", type_at_pos(&db, pos)); } +#[test] +fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { + let (db, pos) = TestDB::with_position( + r#" +//- /main.rs crate:main deps:foo +use foo::Trait; + +fn test() { + let msg = foo::Message(foo::MessageRef); + let r = msg.deref(); + r<|>; +} + +//- /lib.rs crate:foo +pub struct MessageRef; +pub struct Message(MessageRef); + +pub trait Trait { + type Target; + fn deref(&self) -> &Self::Target; +} + +#[macro_export] +macro_rules! expand { + () => { + impl Trait for Message { + type Target = $crate::MessageRef; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + } +} + +expand!(); +"#, + ); + assert_eq!("&MessageRef", type_at_pos(&db, pos)); +} + #[test] fn infer_type_value_non_legacy_macro_use_as() { assert_snapshot!( -- cgit v1.2.3 From fd030f9450ed6910677e30f8fa65b06e71fcffa2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 2 May 2020 01:12:37 +0200 Subject: Revert "Merge #4233" This reverts commit a5f2b16366f027ad60c58266a66eb7fbdcbda9f9, reversing changes made to c96b2180c1c4206a0a98c280b4d30897eb116336. --- crates/ra_hir_ty/src/infer/expr.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index efc60986b..83f946eee 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs @@ -73,6 +73,11 @@ impl<'a> InferenceContext<'a> { self.coerce_merge_branch(&then_ty, &else_ty) } Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), + Expr::TryBlock { body } => { + let _inner = self.infer_expr(*body, expected); + // FIXME should be std::result::Result<{inner}, _> + Ty::Unknown + } Expr::Loop { body } => { self.infer_expr(*body, &Expectation::has_type(Ty::unit())); // FIXME handle break with value -- cgit v1.2.3 From b58dfd24f1bf1f30128fa9a78368b4d430e10e97 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 2 May 2020 11:27:28 +0200 Subject: Add smoke test for decorated blocks --- crates/ra_hir_ty/src/tests/simple.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'crates/ra_hir_ty/src') diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 56abc65b8..3d3088965 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs @@ -1755,3 +1755,35 @@ fn main() { "### ); } + +#[test] +fn effects_smoke_test() { + assert_snapshot!( + infer(r#" +fn main() { + let x = unsafe { 92 }; + let y = async { async { () }.await }; + let z = try { () }; + let t = 'a: { 92 }; +} +"#), + @r###" + 11..131 '{ ...2 }; }': () + 21..22 'x': i32 + 32..38 '{ 92 }': i32 + 34..36 '92': i32 + 48..49 'y': {unknown} + 58..80 '{ asyn...wait }': {unknown} + 60..78 'async ....await': {unknown} + 66..72 '{ () }': () + 68..70 '()': () + 90..91 'z': {unknown} + 94..104 'try { () }': {unknown} + 98..104 '{ () }': () + 100..102 '()': () + 114..115 't': i32 + 122..128 '{ 92 }': i32 + 124..126 '92': i32 + "### + ) +} -- cgit v1.2.3