//! HIR for references to types. Paths in these are not yet resolved. They can
//! be directly created from an ast::TypeRef, without further queries.
-use hir_expand::name::Name;
+
+use hir_expand::{name::Name, AstId, InFile};
+use std::convert::TryInto;
use syntax::ast;
use crate::{body::LowerCtx, path::Path};
}
}
}
+
/// Compare ty::Ty
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum TypeRef {
Path(Path),
RawPtr(Box<TypeRef>, Mutability),
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
- Array(Box<TypeRef> /*, Expr*/),
+ Array(Box<TypeRef>, ConstScalar),
Slice(Box<TypeRef>),
/// A fn pointer. Last element of the vector is the return type.
Fn(Vec<TypeRef>, bool /*varargs*/),
// For
ImplTrait(Vec<TypeBound>),
DynTrait(Vec<TypeBound>),
+ Macro(AstId<ast::MacroCall>),
Error,
}
impl TypeRef {
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
- pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
+ pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
match node {
ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
ast::Type::TupleType(inner) => {
TypeRef::RawPtr(Box::new(inner_ty), mutability)
}
ast::Type::ArrayType(inner) => {
- TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
+ let len = inner
+ .expr()
+ .map(ConstScalar::usize_from_literal_expr)
+ .unwrap_or(ConstScalar::Unknown);
+
+ TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())), len)
}
ast::Type::SliceType(inner) => {
TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
ast::Type::DynTraitType(inner) => {
TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
}
- // FIXME: Macros in type position are not yet supported.
- ast::Type::MacroType(_) => TypeRef::Error,
+ ast::Type::MacroType(mt) => match mt.macro_call() {
+ Some(mc) => ctx
+ .ast_id(&mc)
+ .map(|mc| TypeRef::Macro(InFile::new(ctx.file_id(), mc)))
+ .unwrap_or(TypeRef::Error),
+ None => TypeRef::Error,
+ },
}
}
}
TypeRef::RawPtr(type_ref, _)
| TypeRef::Reference(type_ref, ..)
- | TypeRef::Array(type_ref)
+ | TypeRef::Array(type_ref, _)
| TypeRef::Slice(type_ref) => go(&type_ref, f),
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
for bound in bounds {
}
}
TypeRef::Path(path) => go_path(path, f),
- TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {}
+ TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
};
}
}
}
}
+
+/// A concrete constant value
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum ConstScalar {
+ // for now, we only support the trivial case of constant evaluating the length of an array
+ // Note that this is u64 because the target usize may be bigger than our usize
+ Usize(u64),
+
+ /// Case of an unknown value that rustc might know but we don't
+ Unknown,
+}
+
+impl std::fmt::Display for ConstScalar {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ match self {
+ ConstScalar::Usize(us) => write!(fmt, "{}", us),
+ ConstScalar::Unknown => write!(fmt, "_"),
+ }
+ }
+}
+
+impl ConstScalar {
+ fn usize_from_literal_expr(expr: ast::Expr) -> ConstScalar {
+ match expr {
+ ast::Expr::Literal(lit) => {
+ let lkind = lit.kind();
+ match lkind {
+ ast::LiteralKind::IntNumber(num)
+ if num.suffix() == None || num.suffix() == Some("usize") =>
+ {
+ num.value().and_then(|v| v.try_into().ok())
+ }
+ _ => None,
+ }
+ }
+ _ => None,
+ }
+ .map(ConstScalar::Usize)
+ .unwrap_or(ConstScalar::Unknown)
+ }
+}