//! - 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, 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,
- traits::chalk::{Interner, ToChalk},
+ 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,
- variant_data, Generics,
+ 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, Ty, TyBuilder, TyKind, TypeWalk, 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)]
/// 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
/// 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,
impl_trait_counter,
type_param_mode,
opaque_type_data,
+ expander: RefCell::new(None),
}
}
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
}
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);
}
}
}
+ 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)
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)
}
};
// We need to shift in the bound vars, since
// associated_type_shorthand_candidates does not do that
- let substs = substs.shifted_in_from(self.in_binders);
+ let substs = substs.shifted_in_from(&Interner, self.in_binders);
// FIXME handle type parameters on the segment
return Some(
TyKind::Alias(AliasTy::Projection(ProjectionTy {
// FIXME: how to correctly handle higher-ranked bounds here?
WhereClause::Implemented(tr) => search(
tr.clone()
- .shifted_out_to(DebruijnIndex::ONE)
+ .shifted_out_to(&Interner, DebruijnIndex::ONE)
.expect("FIXME unexpected higher-ranked trait bound"),
),
_ => None,
db: &dyn HirDatabase,
variant_id: VariantId,
) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
- let var_data = variant_data(db.upcast(), variant_id);
+ let var_data = variant_id.variant_data(db.upcast());
let (resolver, def): (_, GenericDefId) = match variant_id {
VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()),
VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()),
traits_in_scope
.push((tr.self_type_parameter(&Interner).clone(), tr.hir_trait_id()));
}
- let program_clause: chalk_ir::ProgramClause<Interner> =
- pred.clone().to_chalk(db).cast(&Interner);
+ let program_clause: chalk_ir::ProgramClause<Interner> = pred.clone().cast(&Interner);
clauses.push(program_clause.into_from_env_clause(&Interner));
}
}
let substs = TyBuilder::type_params_subst(db, trait_id);
let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
let pred = WhereClause::Implemented(trait_ref);
- let program_clause: chalk_ir::ProgramClause<Interner> = pred.to_chalk(db).cast(&Interner);
+ let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
clauses.push(program_clause.into_from_env_clause(&Interner));
}
p.default.as_ref().map_or(TyKind::Error.intern(&Interner), |t| ctx.lower_ty(t));
// Each default can only refer to previous parameters.
- ty = ty.fold_binders(
- &mut |ty, binders| match ty.kind(&Interner) {
- TyKind::BoundVar(BoundVar { debruijn, index }) if *debruijn == binders => {
- if *index >= idx {
- // type variable default referring to parameter coming
- // after it. This is forbidden (FIXME: report
- // diagnostic)
- TyKind::Error.intern(&Interner)
- } else {
- ty
- }
- }
- _ => ty,
- },
- DebruijnIndex::INNERMOST,
- );
+ ty = crate::fold_free_vars(ty, |bound, binders| {
+ if bound.index >= idx && bound.debruijn == DebruijnIndex::INNERMOST {
+ // type variable default referring to parameter coming
+ // after it. This is forbidden (FIXME: report
+ // diagnostic)
+ TyKind::Error.intern(&Interner)
+ } else {
+ bound.shifted_in_from(binders).to_ty(&Interner)
+ }
+ });
+
+ crate::make_only_type_binders(idx, ty)
+ })
+ .collect();
+
+ 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)
})
}
}
-fn make_binders<T>(generics: &Generics, value: T) -> Binders<T> {
+fn make_binders<T: HasInterner<Interner = Interner>>(generics: &Generics, value: T) -> Binders<T> {
crate::make_only_type_binders(generics.len(), value)
}