]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_ty/src/lower.rs
Add lowering of array lengths in types
[rust.git] / crates / hir_ty / src / lower.rs
index 0cdded3e1b65a92629ae9d023c676975af116cce..f7015e5ff9ac310210d1a9c39767887f85b4386b 100644 (file)
@@ -5,12 +5,16 @@
 //!  - 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 chalk_ir::{
+    cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety, Scalar, UintTy,
+};
 use hir_def::{
     adt::StructKind,
+    body::{Expander, LowerCtx},
     builtin_type::BuiltinType,
     generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
     path::{GenericArg, Path, PathSegment, PathSegments},
     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,
-    dummy_usize_const, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
-    chalk_db::ToChalk,
-    Interner,
+    mapping::ToChalk,
+    static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
     utils::{
         all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics,
     },
-    AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
-    FnSubst, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
-    QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
-    TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
+    AliasEq, AliasTy, Binders, BoundVar, CallableSig, ConstData, ConstValue, DebruijnIndex, DynTy,
+    FnPointer, FnSig, FnSubst, ImplTraitId, Interner, OpaqueTy, PolyFnSig, ProjectionTy,
+    QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits,
+    Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
 };
 
 #[derive(Debug)]
@@ -50,7 +54,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<u16>,
+    impl_trait_counter: Cell<u16>,
     /// 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 +63,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<Vec<ReturnTypeImplTrait>>,
+    opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
+    expander: RefCell<Option<Expander>>,
 }
 
 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 +82,7 @@ pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
             impl_trait_counter,
             type_param_mode,
             opaque_type_data,
+            expander: RefCell::new(None),
         }
     }
 
@@ -86,15 +92,18 @@ pub fn with_debruijn<T>(
         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
     }
 
@@ -164,9 +173,16 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
                 let inner_ty = self.lower_ty(inner);
                 TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(&Interner)
             }
-            TypeRef::Array(inner) => {
+            TypeRef::Array(inner, len) => {
                 let inner_ty = self.lower_ty(inner);
-                TyKind::Array(inner_ty, dummy_usize_const()).intern(&Interner)
+
+                let const_len = ConstData {
+                    ty: TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
+                    value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: *len }),
+                }
+                .intern(&Interner);
+
+                TyKind::Array(inner_ty, const_len).intern(&Interner)
             }
             TypeRef::Slice(inner) => {
                 let inner_ty = self.lower_ty(inner);
@@ -287,6 +303,53 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
                     }
                 }
             }
+            TypeRef::Macro(macro_call) => {
+                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(),
+                                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::<ast::Type>(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 {
+                    None
+                };
+                if recursion_start {
+                    *self.expander.borrow_mut() = None;
+                }
+                ty.unwrap_or_else(|| TyKind::Error.intern(&Interner))
+            }
             TypeRef::Error => TyKind::Error.intern(&Interner),
         };
         (ty, res)
@@ -359,17 +422,16 @@ pub(crate) fn lower_partly_resolved_path(
                     self.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty);
                 let ty = if remaining_segments.len() == 1 {
                     let segment = remaining_segments.first().unwrap();
-                    let found = associated_type_by_name_including_super_traits(
-                        self.db,
-                        trait_ref,
-                        &segment.name,
-                    );
+                    let found = self
+                        .db
+                        .trait_data(trait_ref.hir_trait_id())
+                        .associated_type_by_name(&segment.name);
                     match found {
-                        Some((super_trait_ref, associated_ty)) => {
+                        Some(associated_ty) => {
                             // FIXME handle type parameters on the segment
                             TyKind::Alias(AliasTy::Projection(ProjectionTy {
                                 associated_ty_id: to_assoc_type_id(associated_ty),
-                                substitution: super_trait_ref.substitution,
+                                substitution: trait_ref.substitution,
                             }))
                             .intern(&Interner)
                         }
@@ -1034,6 +1096,27 @@ pub(crate) fn generic_defaults_query(
     defaults
 }
 
+pub(crate) fn generic_defaults_recover(
+    db: &dyn HirDatabase,
+    _cycle: &[String],
+    def: &GenericDefId,
+) -> Arc<[Binders<Ty>]> {
+    let generic_params = generics(db.upcast(), *def);
+
+    // we still need one default per parameter
+    let defaults = generic_params
+        .iter()
+        .enumerate()
+        .map(|(idx, _)| {
+            let ty = TyKind::Error.intern(&Interner);
+
+            crate::make_only_type_binders(idx, ty)
+        })
+        .collect();
+
+    defaults
+}
+
 fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
     let data = db.function_data(def);
     let resolver = def.resolver(db.upcast());