1 //! HIR for references to types. Paths in these are not yet resolved. They can
2 //! be directly created from an ast::TypeRef, without further queries.
4 use hir_expand::{ast_id_map::FileAstId, name::Name, ExpandResult, InFile};
8 body::{Expander, LowerCtx},
14 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
21 pub fn from_mutable(mutable: bool) -> Mutability {
29 pub fn as_keyword_for_ref(self) -> &'static str {
31 Mutability::Shared => "",
32 Mutability::Mut => "mut ",
36 pub fn as_keyword_for_ptr(self) -> &'static str {
38 Mutability::Shared => "const ",
39 Mutability::Mut => "mut ",
44 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
51 pub fn from_raw(is_raw: bool) -> Rawness {
60 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
66 /// Converts an `ast::PathType` to a `hir::TraitRef`.
67 pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Option<Self> {
68 // FIXME: Use `Path::from_src`
70 ast::Type::PathType(path) => {
71 path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path })
79 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
85 RawPtr(Box<TypeRef>, Mutability),
86 Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
87 Array(Box<TypeRef> /*, Expr*/),
89 /// A fn pointer. Last element of the vector is the return type.
90 Fn(Vec<TypeRef>, bool /*varargs*/),
92 ImplTrait(Vec<TypeBound>),
93 DynTrait(Vec<TypeBound>),
94 Macro(InFile<FileAstId<ast::MacroCall>>),
98 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
99 pub struct LifetimeRef {
104 pub(crate) fn new_name(name: Name) -> Self {
108 pub(crate) fn new(lifetime: &ast::Lifetime) -> Self {
109 LifetimeRef { name: Name::new_lifetime(lifetime) }
112 pub fn missing() -> LifetimeRef {
113 LifetimeRef { name: Name::missing() }
117 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
120 // ForLifetime(Vec<LifetimeRef>, Path), FIXME ForLifetime
121 Lifetime(LifetimeRef),
126 /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
127 pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
129 ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
130 ast::Type::TupleType(inner) => {
131 TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
133 ast::Type::NeverType(..) => TypeRef::Never,
134 ast::Type::PathType(inner) => {
135 // FIXME: Use `Path::from_src`
138 .and_then(|it| ctx.lower_path(it))
140 .unwrap_or(TypeRef::Error)
142 ast::Type::PtrType(inner) => {
143 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty());
144 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
145 TypeRef::RawPtr(Box::new(inner_ty), mutability)
147 ast::Type::ArrayType(inner) => {
148 TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
150 ast::Type::SliceType(inner) => {
151 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
153 ast::Type::RefType(inner) => {
154 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty());
155 let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(<));
156 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
157 TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
159 ast::Type::InferType(_inner) => TypeRef::Placeholder,
160 ast::Type::FnPtrType(inner) => {
163 .and_then(|rt| rt.ty())
164 .map(|it| TypeRef::from_ast(ctx, it))
165 .unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
166 let mut is_varargs = false;
167 let mut params = if let Some(pl) = inner.param_list() {
168 if let Some(param) = pl.params().last() {
169 is_varargs = param.dotdotdot_token().is_some();
172 pl.params().map(|p| p.ty()).map(|it| TypeRef::from_ast_opt(&ctx, it)).collect()
177 TypeRef::Fn(params, is_varargs)
179 // for types are close enough for our purposes to the inner type for now...
180 ast::Type::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
181 ast::Type::ImplTraitType(inner) => {
182 TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
184 ast::Type::DynTraitType(inner) => {
185 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
187 ast::Type::MacroType(mt) => match mt.macro_call() {
190 .map(|mc| TypeRef::Macro(InFile::new(ctx.file_id(), mc)))
191 .unwrap_or(TypeRef::Error),
192 None => TypeRef::Error,
197 pub(crate) fn from_ast_opt(ctx: &LowerCtx, node: Option<ast::Type>) -> Self {
198 if let Some(node) = node {
199 TypeRef::from_ast(ctx, node)
205 pub(crate) fn unit() -> TypeRef {
206 TypeRef::Tuple(Vec::new())
209 pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
212 fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
215 TypeRef::Fn(types, _) | TypeRef::Tuple(types) => {
216 types.iter().for_each(|t| go(t, f))
218 TypeRef::RawPtr(type_ref, _)
219 | TypeRef::Reference(type_ref, ..)
220 | TypeRef::Array(type_ref)
221 | TypeRef::Slice(type_ref) => go(&type_ref, f),
222 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
223 for bound in bounds {
225 TypeBound::Path(path) => go_path(path, f),
226 TypeBound::Lifetime(_) | TypeBound::Error => (),
230 TypeRef::Path(path) => go_path(path, f),
231 TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
235 fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
236 if let Some(type_ref) = path.type_anchor() {
239 for segment in path.segments().iter() {
240 if let Some(args_and_bindings) = segment.args_and_bindings {
241 for arg in &args_and_bindings.args {
243 crate::path::GenericArg::Type(type_ref) => {
246 crate::path::GenericArg::Lifetime(_) => {}
249 for binding in &args_and_bindings.bindings {
250 if let Some(type_ref) = &binding.type_ref {
253 for bound in &binding.bounds {
255 TypeBound::Path(path) => go_path(path, f),
256 TypeBound::Lifetime(_) | TypeBound::Error => (),
266 pub(crate) fn type_bounds_from_ast(
267 lower_ctx: &LowerCtx,
268 type_bounds_opt: Option<ast::TypeBoundList>,
269 ) -> Vec<TypeBound> {
270 if let Some(type_bounds) = type_bounds_opt {
271 type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
278 pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeBound) -> Self {
280 ast::TypeBoundKind::PathType(path_type) => {
281 let path = match path_type.path() {
283 None => return TypeBound::Error,
286 let path = match ctx.lower_path(path) {
288 None => return TypeBound::Error,
290 TypeBound::Path(path)
292 ast::TypeBoundKind::ForType(_) => TypeBound::Error, // FIXME ForType
293 ast::TypeBoundKind::Lifetime(lifetime) => {
294 TypeBound::Lifetime(LifetimeRef::new(&lifetime))
299 pub fn as_path(&self) -> Option<&Path> {
301 TypeBound::Path(p) => Some(p),
307 pub fn expand_macro_type(
308 db: &dyn DefDatabase,
310 macro_type: &TypeRef,
311 ) -> Option<TypeRef> {
312 let macro_call = match macro_type {
313 TypeRef::Macro(macro_call) => macro_call,
314 _ => panic!("expected TypeRef::Macro"),
317 let file_id = macro_call.file_id;
318 let macro_call = macro_call.to_node(db.upcast());
320 let mut expander = Expander::new(db, file_id, module_id);
321 let (file_id, expanded) = match expander.enter_expand::<ast::Type>(db, macro_call.clone()) {
322 Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
323 let file_id = expander.current_file_id();
324 expander.exit(db, mark);
330 let ctx = LowerCtx::new(db, file_id);
331 return Some(TypeRef::from_ast(&ctx, expanded));