From cf3b4f1e208247c9d171273dabff9c6b3c98a240 Mon Sep 17 00:00:00 2001 From: cynecx Date: Sat, 10 Apr 2021 17:49:12 +0200 Subject: hir_ty: Expand macros at type position --- crates/hir_ty/src/display.rs | 2 +- crates/hir_ty/src/lower.rs | 12 ++- crates/hir_ty/src/tests/macros.rs | 169 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+), 2 deletions(-) (limited to 'crates/hir_ty/src') diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index e7c9dabc2..63bcb0640 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs @@ -997,7 +997,7 @@ impl HirDisplay for TypeRef { write!(f, "dyn ")?; f.write_joined(bounds, " + ")?; } - TypeRef::Error => write!(f, "{{error}}")?, + TypeRef::Error | TypeRef::Macro(_) => write!(f, "{{error}}")?, } Ok(()) } diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index a035686bc..95ca5bdb0 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs @@ -15,7 +15,7 @@ use hir_def::{ generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, - type_ref::{TraitRef as HirTraitRef, TypeBound, TypeRef}, + type_ref::{expand_type_ref, TraitRef as HirTraitRef, TypeBound, TypeRef}, AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, @@ -287,6 +287,16 @@ impl<'a> TyLoweringContext<'a> { } } } + mt @ TypeRef::Macro(_) => { + if let Some(module_id) = self.resolver.module() { + match expand_type_ref(self.db.upcast(), module_id, mt) { + Some(type_ref) => self.lower_ty(type_ref.as_ref()), + None => TyKind::Error.intern(&Interner), + } + } else { + TyKind::Error.intern(&Interner) + } + } TypeRef::Error => TyKind::Error.intern(&Interner), }; (ty, res) diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index b8e373ed8..cbe05a5c1 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs @@ -1074,3 +1074,172 @@ fn macro_in_arm() { "#]], ); } + +#[test] +fn macro_in_type_alias_position() { + check_infer( + r#" + macro_rules! U32 { + () => { u32 }; + } + + trait Foo { + type Ty; + } + + impl Foo for T { + type Ty = U32!(); + } + + type TayTo = U32!(); + + fn testy() { + let a: <() as Foo>::Ty; + let b: TayTo; + } + "#, + expect![[r#" + 147..196 '{ ...yTo; }': () + 157..158 'a': u32 + 185..186 'b': u32 + "#]], + ); +} + +#[test] +fn nested_macro_in_type_alias_position() { + check_infer( + r#" + macro_rules! U32Inner2 { + () => { u32 }; + } + + macro_rules! U32Inner1 { + () => { U32Inner2!() }; + } + + macro_rules! U32 { + () => { U32Inner1!() }; + } + + trait Foo { + type Ty; + } + + impl Foo for T { + type Ty = U32!(); + } + + type TayTo = U32!(); + + fn testy() { + let a: <() as Foo>::Ty; + let b: TayTo; + } + "#, + expect![[r#" + 259..308 '{ ...yTo; }': () + 269..270 'a': u32 + 297..298 'b': u32 + "#]], + ); +} + +#[test] +fn macros_in_type_alias_position_generics() { + check_infer( + r#" + struct Foo(A, B); + + macro_rules! U32 { + () => { u32 }; + } + + macro_rules! Bar { + () => { Foo }; + } + + trait Moo { + type Ty; + } + + impl Moo for T { + type Ty = Bar!(); + } + + type TayTo = Bar!(); + + fn main() { + let a: <() as Moo>::Ty; + let b: TayTo; + } + "#, + expect![[r#" + 228..277 '{ ...yTo; }': () + 238..239 'a': Foo + 266..267 'b': Foo + "#]], + ); +} + +#[test] +fn macros_in_type_position() { + check_infer( + r#" + struct Foo(A, B); + + macro_rules! U32 { + () => { u32 }; + } + + macro_rules! Bar { + () => { Foo }; + } + + fn main() { + let a: Bar!(); + } + "#, + expect![[r#" + 133..155 '{ ...!(); }': () + 143..144 'a': Foo + "#]], + ); +} + +#[test] +fn macros_in_type_generics() { + check_infer( + r#" + struct Foo(A, B); + + macro_rules! U32 { + () => { u32 }; + } + + macro_rules! Bar { + () => { Foo }; + } + + trait Moo { + type Ty; + } + + impl Moo for T { + type Ty = Foo; + } + + type TayTo = Foo; + + fn main() { + let a: <() as Moo>::Ty; + let b: TayTo; + } + "#, + expect![[r#" + 254..303 '{ ...yTo; }': () + 264..265 'a': Foo, Foo> + 292..293 'b': Foo, u32> + "#]], + ); +} -- cgit v1.2.3 From 28ef7c20d79803403be58eeffa18ab1fb21e261c Mon Sep 17 00:00:00 2001 From: cynecx Date: Mon, 12 Apr 2021 16:24:48 +0200 Subject: hir_ty: deal with TypeRef::Macro in HirFormatter --- crates/hir_ty/src/display.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'crates/hir_ty/src') diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 63bcb0640..4fb7d9cf2 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs @@ -9,6 +9,7 @@ use std::{ use chalk_ir::BoundVar; use hir_def::{ + body, db::DefDatabase, find_path, generics::TypeParamProvenance, @@ -18,7 +19,7 @@ use hir_def::{ visibility::Visibility, AssocContainerId, Lookup, ModuleId, TraitId, }; -use hir_expand::name::Name; +use hir_expand::{hygiene::Hygiene, name::Name}; use crate::{ const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id, @@ -997,7 +998,19 @@ impl HirDisplay for TypeRef { write!(f, "dyn ")?; f.write_joined(bounds, " + ")?; } - TypeRef::Error | TypeRef::Macro(_) => write!(f, "{{error}}")?, + TypeRef::Macro(macro_call) => { + let macro_call = macro_call.to_node(f.db.upcast()); + let ctx = body::LowerCtx::with_hygiene(&Hygiene::new_unhygienic()); + match macro_call.path() { + Some(path) => match Path::from_src(path, &ctx) { + Some(path) => path.hir_fmt(f)?, + None => write!(f, "{{macro}}")?, + }, + None => write!(f, "{{macro}}")?, + } + write!(f, "!(..)")?; + } + TypeRef::Error => write!(f, "{{error}}")?, } Ok(()) } -- cgit v1.2.3 From 7ed42a3a527b2c39826cfeb3626521c11abb25f0 Mon Sep 17 00:00:00 2001 From: cynecx Date: Sat, 17 Apr 2021 17:38:38 +0200 Subject: hir_def: refactor expand_macro_type and cleanups --- crates/hir_ty/src/lower.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/hir_ty/src') diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 95ca5bdb0..e01b7aa91 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs @@ -15,7 +15,7 @@ use hir_def::{ generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, - type_ref::{expand_type_ref, TraitRef as HirTraitRef, TypeBound, TypeRef}, + type_ref::{expand_macro_type, TraitRef as HirTraitRef, TypeBound, TypeRef}, AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, @@ -289,8 +289,8 @@ impl<'a> TyLoweringContext<'a> { } mt @ TypeRef::Macro(_) => { if let Some(module_id) = self.resolver.module() { - match expand_type_ref(self.db.upcast(), module_id, mt) { - Some(type_ref) => self.lower_ty(type_ref.as_ref()), + match expand_macro_type(self.db.upcast(), module_id, mt) { + Some(type_ref) => self.lower_ty(&type_ref), None => TyKind::Error.intern(&Interner), } } else { -- cgit v1.2.3 From 6ed2fd233b569d01169fc888f30c358dd289d260 Mon Sep 17 00:00:00 2001 From: cynecx Date: Sun, 18 Apr 2021 19:56:13 +0200 Subject: hir_ty: keep body::Expander in TyLoweringContext --- crates/hir_ty/src/lower.rs | 71 +++++++++++++++++++++++++++++++-------- crates/hir_ty/src/tests/macros.rs | 26 ++++++++++++++ 2 files changed, 83 insertions(+), 14 deletions(-) (limited to 'crates/hir_ty/src') diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index e01b7aa91..a883334af 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs @@ -5,25 +5,28 @@ //! - Building the type for an item: This happens through the `type_for_def` query. //! //! This usually involves resolving names, collecting generic arguments etc. +use std::cell::{Cell, RefCell}; use std::{iter, sync::Arc}; use base_db::CrateId; use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; use hir_def::{ adt::StructKind, + body::{Expander, LowerCtx}, builtin_type::BuiltinType, generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, path::{GenericArg, Path, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, - type_ref::{expand_macro_type, TraitRef as HirTraitRef, TypeBound, TypeRef}, + type_ref::{TraitRef as HirTraitRef, TypeBound, TypeRef}, AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, VariantId, }; -use hir_expand::name::Name; +use hir_expand::{name::Name, ExpandResult}; use la_arena::ArenaMap; use smallvec::SmallVec; use stdx::impl_from; +use syntax::ast; use crate::{ db::HirDatabase, @@ -50,7 +53,7 @@ pub struct TyLoweringContext<'a> { /// possible currently, so this should be fine for now. pub type_param_mode: TypeParamLoweringMode, pub impl_trait_mode: ImplTraitLoweringMode, - impl_trait_counter: std::cell::Cell, + impl_trait_counter: Cell, /// When turning `impl Trait` into opaque types, we have to collect the /// bounds at the same time to get the IDs correct (without becoming too /// complicated). I don't like using interior mutability (as for the @@ -59,16 +62,17 @@ pub struct TyLoweringContext<'a> { /// we're grouping the mutable data (the counter and this field) together /// with the immutable context (the references to the DB and resolver). /// Splitting this up would be a possible fix. - opaque_type_data: std::cell::RefCell>, + opaque_type_data: RefCell>, + expander: RefCell>, } impl<'a> TyLoweringContext<'a> { pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { - let impl_trait_counter = std::cell::Cell::new(0); + let impl_trait_counter = Cell::new(0); let impl_trait_mode = ImplTraitLoweringMode::Disallowed; let type_param_mode = TypeParamLoweringMode::Placeholder; let in_binders = DebruijnIndex::INNERMOST; - let opaque_type_data = std::cell::RefCell::new(Vec::new()); + let opaque_type_data = RefCell::new(Vec::new()); Self { db, resolver, @@ -77,6 +81,7 @@ impl<'a> TyLoweringContext<'a> { impl_trait_counter, type_param_mode, opaque_type_data, + expander: RefCell::new(None), } } @@ -86,15 +91,18 @@ impl<'a> TyLoweringContext<'a> { f: impl FnOnce(&TyLoweringContext) -> T, ) -> T { let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new()); + let expander = self.expander.replace(None); let new_ctx = Self { in_binders: debruijn, - impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), - opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec), + impl_trait_counter: Cell::new(self.impl_trait_counter.get()), + opaque_type_data: RefCell::new(opaque_ty_data_vec), + expander: RefCell::new(expander), ..*self }; let result = f(&new_ctx); self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); + self.expander.replace(new_ctx.expander.into_inner()); result } @@ -287,15 +295,50 @@ impl<'a> TyLoweringContext<'a> { } } } - mt @ TypeRef::Macro(_) => { - if let Some(module_id) = self.resolver.module() { - match expand_macro_type(self.db.upcast(), module_id, mt) { - Some(type_ref) => self.lower_ty(&type_ref), - None => TyKind::Error.intern(&Interner), + TypeRef::Macro(macro_call) => { + let (expander, recursion_start) = match self.expander.borrow_mut() { + expander if expander.is_some() => (Some(expander), false), + mut expander => { + if let Some(module_id) = self.resolver.module() { + *expander = Some(Expander::new( + self.db.upcast(), + macro_call.file_id, + module_id, + )); + (Some(expander), true) + } else { + (None, false) + } + } + }; + let ty = if let Some(mut expander) = expander { + let expander_mut = expander.as_mut().unwrap(); + let macro_call = macro_call.to_node(self.db.upcast()); + match expander_mut.enter_expand::(self.db.upcast(), macro_call) { + Ok(ExpandResult { value: Some((mark, expanded)), .. }) => { + let ctx = + LowerCtx::new(self.db.upcast(), expander_mut.current_file_id()); + let type_ref = TypeRef::from_ast(&ctx, expanded); + + drop(expander); + let ty = self.lower_ty(&type_ref); + + self.expander + .borrow_mut() + .as_mut() + .unwrap() + .exit(self.db.upcast(), mark); + Some(ty) + } + _ => None, } } else { - TyKind::Error.intern(&Interner) + None + }; + if recursion_start { + *self.expander.borrow_mut() = None; } + ty.unwrap_or_else(|| TyKind::Error.intern(&Interner)) } TypeRef::Error => TyKind::Error.intern(&Interner), }; diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index cbe05a5c1..8de1e229f 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs @@ -1243,3 +1243,29 @@ fn macros_in_type_generics() { "#]], ); } + +#[test] +fn infinitely_recursive_macro_type() { + check_infer( + r#" + struct Bar(T); + + macro_rules! Foo { + () => { Foo!() } + } + + type A = Foo!(); + type B = Bar; + + fn main() { + let a: A; + let b: B; + } + "#, + expect![[r#" + 112..143 '{ ...: B; }': () + 122..123 'a': {unknown} + 136..137 'b': Bar<{unknown}> + "#]], + ); +} -- cgit v1.2.3 From f0507ab7c697ba4bcd59dd2f673dfff5072e3e1a Mon Sep 17 00:00:00 2001 From: cynecx Date: Sun, 18 Apr 2021 20:18:48 +0200 Subject: hir_ty: cleanups and extend infinitely_recursive_macro_type test --- crates/hir_ty/src/lower.rs | 8 +++++--- crates/hir_ty/src/tests/macros.rs | 14 +++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'crates/hir_ty/src') diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index a883334af..7fd46becd 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs @@ -296,9 +296,11 @@ impl<'a> TyLoweringContext<'a> { } } TypeRef::Macro(macro_call) => { - let (expander, recursion_start) = match self.expander.borrow_mut() { - expander if expander.is_some() => (Some(expander), false), - mut expander => { + let (expander, recursion_start) = { + let mut expander = self.expander.borrow_mut(); + if expander.is_some() { + (Some(expander), false) + } else { if let Some(module_id) = self.resolver.module() { *expander = Some(Expander::new( self.db.upcast(), diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index 8de1e229f..6588aa46c 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs @@ -1248,14 +1248,18 @@ fn macros_in_type_generics() { fn infinitely_recursive_macro_type() { check_infer( r#" - struct Bar(T); + struct Bar(T, X); macro_rules! Foo { () => { Foo!() } } + macro_rules! U32 { + () => { u32 } + } + type A = Foo!(); - type B = Bar; + type B = Bar; fn main() { let a: A; @@ -1263,9 +1267,9 @@ fn infinitely_recursive_macro_type() { } "#, expect![[r#" - 112..143 '{ ...: B; }': () - 122..123 'a': {unknown} - 136..137 'b': Bar<{unknown}> + 166..197 '{ ...: B; }': () + 176..177 'a': {unknown} + 190..191 'b': Bar<{unknown}, u32> "#]], ); } -- cgit v1.2.3