mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 22:01:37 +00:00
⬆️ rust-analyzer
This commit is contained in:
parent
3a57388d13
commit
4f55ebbd4f
122 changed files with 2885 additions and 1093 deletions
|
@ -123,13 +123,14 @@ fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
|
|||
let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
|
||||
|
||||
let projection = {
|
||||
let b = TyBuilder::assoc_type_projection(db, target);
|
||||
let b = TyBuilder::subst_for_def(db, deref_trait, None);
|
||||
if b.remaining() != 1 {
|
||||
// the Target type + Deref trait should only have one generic parameter,
|
||||
// namely Deref's Self type
|
||||
return None;
|
||||
}
|
||||
b.push(ty).build()
|
||||
let deref_subst = b.push(ty).build();
|
||||
TyBuilder::assoc_type_projection(db, target, Some(deref_subst)).build()
|
||||
};
|
||||
|
||||
// Check that the type implements Deref at all
|
||||
|
|
|
@ -6,19 +6,19 @@ use chalk_ir::{
|
|||
cast::{Cast, CastTo, Caster},
|
||||
fold::TypeFoldable,
|
||||
interner::HasInterner,
|
||||
AdtId, BoundVar, DebruijnIndex, Scalar,
|
||||
AdtId, DebruijnIndex, Scalar,
|
||||
};
|
||||
use hir_def::{
|
||||
builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId,
|
||||
TypeAliasId,
|
||||
builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId,
|
||||
GenericDefId, TraitId, TypeAliasId,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{
|
||||
consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
|
||||
to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData,
|
||||
ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty,
|
||||
TyDefId, TyExt, TyKind, ValueTyDefId,
|
||||
to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, BoundVar, CallableSig,
|
||||
GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
|
||||
ValueTyDefId,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -34,17 +34,32 @@ pub struct TyBuilder<D> {
|
|||
data: D,
|
||||
vec: SmallVec<[GenericArg; 2]>,
|
||||
param_kinds: SmallVec<[ParamKind; 2]>,
|
||||
parent_subst: Substitution,
|
||||
}
|
||||
|
||||
impl<A> TyBuilder<A> {
|
||||
fn with_data<B>(self, data: B) -> TyBuilder<B> {
|
||||
TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
|
||||
TyBuilder {
|
||||
data,
|
||||
vec: self.vec,
|
||||
param_kinds: self.param_kinds,
|
||||
parent_subst: self.parent_subst,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> TyBuilder<D> {
|
||||
fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
|
||||
TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
|
||||
fn new(
|
||||
data: D,
|
||||
param_kinds: SmallVec<[ParamKind; 2]>,
|
||||
parent_subst: Option<Substitution>,
|
||||
) -> Self {
|
||||
let parent_subst = parent_subst.unwrap_or_else(|| Substitution::empty(Interner));
|
||||
Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst }
|
||||
}
|
||||
|
||||
fn new_empty(data: D) -> Self {
|
||||
TyBuilder::new(data, SmallVec::new(), None)
|
||||
}
|
||||
|
||||
fn build_internal(self) -> (D, Substitution) {
|
||||
|
@ -52,13 +67,18 @@ impl<D> TyBuilder<D> {
|
|||
for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
|
||||
self.assert_match_kind(a, e);
|
||||
}
|
||||
let subst = Substitution::from_iter(Interner, self.vec);
|
||||
let subst = Substitution::from_iter(
|
||||
Interner,
|
||||
self.vec.into_iter().chain(self.parent_subst.iter(Interner).cloned()),
|
||||
);
|
||||
(self.data, subst)
|
||||
}
|
||||
|
||||
pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
|
||||
assert!(self.remaining() > 0);
|
||||
let arg = arg.cast(Interner);
|
||||
let expected_kind = &self.param_kinds[self.vec.len()];
|
||||
|
||||
let arg_kind = match arg.data(Interner) {
|
||||
chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
|
||||
chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
|
||||
|
@ -68,7 +88,9 @@ impl<D> TyBuilder<D> {
|
|||
}
|
||||
};
|
||||
assert_eq!(*expected_kind, arg_kind);
|
||||
|
||||
self.vec.push(arg);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -79,20 +101,12 @@ impl<D> TyBuilder<D> {
|
|||
pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
|
||||
// self.fill is inlined to make borrow checker happy
|
||||
let mut this = self;
|
||||
let other = this.param_kinds.iter().skip(this.vec.len());
|
||||
let other = &this.param_kinds[this.vec.len()..];
|
||||
let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
|
||||
ParamKind::Type => {
|
||||
GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
|
||||
.intern(Interner)
|
||||
ParamKind::Type => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
|
||||
ParamKind::Const(ty) => {
|
||||
BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
|
||||
}
|
||||
ParamKind::Const(ty) => GenericArgData::Const(
|
||||
ConstData {
|
||||
value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
|
||||
ty: ty.clone(),
|
||||
}
|
||||
.intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
});
|
||||
this.vec.extend(filler.take(this.remaining()).casted(Interner));
|
||||
assert_eq!(this.remaining(), 0);
|
||||
|
@ -102,8 +116,8 @@ impl<D> TyBuilder<D> {
|
|||
pub fn fill_with_unknown(self) -> Self {
|
||||
// self.fill is inlined to make borrow checker happy
|
||||
let mut this = self;
|
||||
let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
|
||||
ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
|
||||
let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
|
||||
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
|
||||
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
|
||||
});
|
||||
this.vec.extend(filler.casted(Interner));
|
||||
|
@ -113,33 +127,17 @@ impl<D> TyBuilder<D> {
|
|||
|
||||
pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
|
||||
self.fill(|x| match x {
|
||||
ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner),
|
||||
ParamKind::Const(ty) => {
|
||||
GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
|
||||
}
|
||||
ParamKind::Type => table.new_type_var().cast(Interner),
|
||||
ParamKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
|
||||
self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
|
||||
self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler));
|
||||
assert_eq!(self.remaining(), 0);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
|
||||
assert!(self.vec.is_empty());
|
||||
assert!(parent_substs.len(Interner) <= self.param_kinds.len());
|
||||
self.extend(parent_substs.iter(Interner).cloned());
|
||||
self
|
||||
}
|
||||
|
||||
fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
|
||||
for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
|
||||
self.assert_match_kind(&x.0, &x.1);
|
||||
}
|
||||
self.vec.extend(it);
|
||||
}
|
||||
|
||||
fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
|
||||
match (a.data(Interner), e) {
|
||||
(chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
|
||||
|
@ -188,21 +186,42 @@ impl TyBuilder<()> {
|
|||
params.placeholder_subst(db)
|
||||
}
|
||||
|
||||
pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
|
||||
let def = def.into();
|
||||
let params = generics(db.upcast(), def);
|
||||
TyBuilder::new(
|
||||
(),
|
||||
params
|
||||
.iter()
|
||||
.map(|(id, data)| match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
pub fn subst_for_def(
|
||||
db: &dyn HirDatabase,
|
||||
def: impl Into<GenericDefId>,
|
||||
parent_subst: Option<Substitution>,
|
||||
) -> TyBuilder<()> {
|
||||
let generics = generics(db.upcast(), def.into());
|
||||
assert!(generics.parent_generics().is_some() == parent_subst.is_some());
|
||||
let params = generics
|
||||
.iter_self()
|
||||
.map(|(id, data)| match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
TyBuilder::new((), params, parent_subst)
|
||||
}
|
||||
|
||||
/// Creates a `TyBuilder` to build `Substitution` for a generator defined in `parent`.
|
||||
///
|
||||
/// A generator's substitution consists of:
|
||||
/// - resume type of generator
|
||||
/// - yield type of generator ([`Generator::Yield`](std::ops::Generator::Yield))
|
||||
/// - return type of generator ([`Generator::Return`](std::ops::Generator::Return))
|
||||
/// - generic parameters in scope on `parent`
|
||||
/// in this order.
|
||||
///
|
||||
/// This method prepopulates the builder with placeholder substitution of `parent`, so you
|
||||
/// should only push exactly 3 `GenericArg`s before building.
|
||||
pub fn subst_for_generator(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
|
||||
let parent_subst =
|
||||
parent.as_generic_def_id().map(|p| generics(db.upcast(), p).placeholder_subst(db));
|
||||
// These represent resume type, yield type, and return type of generator.
|
||||
let params = std::iter::repeat(ParamKind::Type).take(3).collect();
|
||||
TyBuilder::new((), params, parent_subst)
|
||||
}
|
||||
|
||||
pub fn build(self) -> Substitution {
|
||||
|
@ -213,7 +232,7 @@ impl TyBuilder<()> {
|
|||
|
||||
impl TyBuilder<hir_def::AdtId> {
|
||||
pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
|
||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
||||
TyBuilder::subst_for_def(db, def, None).with_data(def)
|
||||
}
|
||||
|
||||
pub fn fill_with_defaults(
|
||||
|
@ -221,16 +240,27 @@ impl TyBuilder<hir_def::AdtId> {
|
|||
db: &dyn HirDatabase,
|
||||
mut fallback: impl FnMut() -> Ty,
|
||||
) -> Self {
|
||||
// Note that we're building ADT, so we never have parent generic parameters.
|
||||
let defaults = db.generic_defaults(self.data.into());
|
||||
let dummy_ty = TyKind::Error.intern(Interner).cast(Interner);
|
||||
for default_ty in defaults.iter().skip(self.vec.len()) {
|
||||
if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
|
||||
// NOTE(skip_binders): we only check if the arg type is error type.
|
||||
if let Some(x) = default_ty.skip_binders().ty(Interner) {
|
||||
if x.is_unknown() {
|
||||
self.vec.push(fallback().cast(Interner));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
// each default can depend on the previous parameters
|
||||
let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
|
||||
}
|
||||
// Each default can only depend on the previous parameters.
|
||||
// FIXME: we don't handle const generics here.
|
||||
let subst_so_far = Substitution::from_iter(
|
||||
Interner,
|
||||
self.vec
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(iter::repeat(dummy_ty.clone()))
|
||||
.take(self.param_kinds.len()),
|
||||
);
|
||||
self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
|
||||
}
|
||||
self
|
||||
|
@ -245,7 +275,7 @@ impl TyBuilder<hir_def::AdtId> {
|
|||
pub struct Tuple(usize);
|
||||
impl TyBuilder<Tuple> {
|
||||
pub fn tuple(size: usize) -> TyBuilder<Tuple> {
|
||||
TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
|
||||
TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect(), None)
|
||||
}
|
||||
|
||||
pub fn build(self) -> Ty {
|
||||
|
@ -256,7 +286,7 @@ impl TyBuilder<Tuple> {
|
|||
|
||||
impl TyBuilder<TraitId> {
|
||||
pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
|
||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
||||
TyBuilder::subst_for_def(db, def, None).with_data(def)
|
||||
}
|
||||
|
||||
pub fn build(self) -> TraitRef {
|
||||
|
@ -266,8 +296,12 @@ impl TyBuilder<TraitId> {
|
|||
}
|
||||
|
||||
impl TyBuilder<TypeAliasId> {
|
||||
pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
|
||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
||||
pub fn assoc_type_projection(
|
||||
db: &dyn HirDatabase,
|
||||
def: TypeAliasId,
|
||||
parent_subst: Option<Substitution>,
|
||||
) -> TyBuilder<TypeAliasId> {
|
||||
TyBuilder::subst_for_def(db, def, parent_subst).with_data(def)
|
||||
}
|
||||
|
||||
pub fn build(self) -> ProjectionTy {
|
||||
|
@ -277,19 +311,6 @@ impl TyBuilder<TypeAliasId> {
|
|||
}
|
||||
|
||||
impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
|
||||
fn subst_binders(b: Binders<T>) -> Self {
|
||||
let param_kinds = b
|
||||
.binders
|
||||
.iter(Interner)
|
||||
.map(|x| match x {
|
||||
chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
|
||||
chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
|
||||
chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
|
||||
})
|
||||
.collect();
|
||||
TyBuilder::new(b, param_kinds)
|
||||
}
|
||||
|
||||
pub fn build(self) -> T {
|
||||
let (b, subst) = self.build_internal();
|
||||
b.substitute(Interner, &subst)
|
||||
|
@ -297,15 +318,41 @@ impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Bin
|
|||
}
|
||||
|
||||
impl TyBuilder<Binders<Ty>> {
|
||||
pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> {
|
||||
TyBuilder::subst_binders(db.ty(def))
|
||||
pub fn def_ty(
|
||||
db: &dyn HirDatabase,
|
||||
def: TyDefId,
|
||||
parent_subst: Option<Substitution>,
|
||||
) -> TyBuilder<Binders<Ty>> {
|
||||
let poly_ty = db.ty(def);
|
||||
let id: GenericDefId = match def {
|
||||
TyDefId::BuiltinType(_) => {
|
||||
assert!(parent_subst.is_none());
|
||||
return TyBuilder::new_empty(poly_ty);
|
||||
}
|
||||
TyDefId::AdtId(id) => id.into(),
|
||||
TyDefId::TypeAliasId(id) => id.into(),
|
||||
};
|
||||
TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
|
||||
}
|
||||
|
||||
pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
|
||||
TyBuilder::subst_binders(db.impl_self_ty(def))
|
||||
TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
|
||||
}
|
||||
|
||||
pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> {
|
||||
TyBuilder::subst_binders(db.value_ty(def))
|
||||
pub fn value_ty(
|
||||
db: &dyn HirDatabase,
|
||||
def: ValueTyDefId,
|
||||
parent_subst: Option<Substitution>,
|
||||
) -> TyBuilder<Binders<Ty>> {
|
||||
let poly_value_ty = db.value_ty(def);
|
||||
let id = match def.to_generic_def_id() {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
// static items
|
||||
assert!(parent_subst.is_none());
|
||||
return TyBuilder::new_empty(poly_value_ty);
|
||||
}
|
||||
};
|
||||
TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_value_ty)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
|
|||
|
||||
use base_db::CrateId;
|
||||
use hir_def::{
|
||||
expr::Movability,
|
||||
lang_item::{lang_attr, LangItemTarget},
|
||||
AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
|
||||
};
|
||||
|
@ -26,9 +27,9 @@ use crate::{
|
|||
to_assoc_type_id, to_chalk_trait_id,
|
||||
traits::ChalkContext,
|
||||
utils::generics,
|
||||
AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy,
|
||||
ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder,
|
||||
TyExt, TyKind, WhereClause,
|
||||
wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId,
|
||||
Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef,
|
||||
TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
|
||||
};
|
||||
|
||||
pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
|
||||
|
@ -372,17 +373,62 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
|||
}
|
||||
fn generator_datum(
|
||||
&self,
|
||||
_: chalk_ir::GeneratorId<Interner>,
|
||||
id: chalk_ir::GeneratorId<Interner>,
|
||||
) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorDatum<Interner>> {
|
||||
// FIXME
|
||||
unimplemented!()
|
||||
let (parent, expr) = self.db.lookup_intern_generator(id.into());
|
||||
|
||||
// We fill substitution with unknown type, because we only need to know whether the generic
|
||||
// params are types or consts to build `Binders` and those being filled up are for
|
||||
// `resume_type`, `yield_type`, and `return_type` of the generator in question.
|
||||
let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
|
||||
|
||||
let input_output = rust_ir::GeneratorInputOutputDatum {
|
||||
resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
|
||||
.intern(Interner),
|
||||
yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 1))
|
||||
.intern(Interner),
|
||||
return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 2))
|
||||
.intern(Interner),
|
||||
// FIXME: calculate upvars
|
||||
upvars: vec![],
|
||||
};
|
||||
|
||||
let it = subst
|
||||
.iter(Interner)
|
||||
.map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
|
||||
let input_output = crate::make_type_and_const_binders(it, input_output);
|
||||
|
||||
let movability = match self.db.body(parent)[expr] {
|
||||
hir_def::expr::Expr::Closure {
|
||||
closure_kind: hir_def::expr::ClosureKind::Generator(movability),
|
||||
..
|
||||
} => movability,
|
||||
_ => unreachable!("non generator expression interned as generator"),
|
||||
};
|
||||
let movability = match movability {
|
||||
Movability::Static => rust_ir::Movability::Static,
|
||||
Movability::Movable => rust_ir::Movability::Movable,
|
||||
};
|
||||
|
||||
Arc::new(rust_ir::GeneratorDatum { movability, input_output })
|
||||
}
|
||||
fn generator_witness_datum(
|
||||
&self,
|
||||
_: chalk_ir::GeneratorId<Interner>,
|
||||
id: chalk_ir::GeneratorId<Interner>,
|
||||
) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorWitnessDatum<Interner>> {
|
||||
// FIXME
|
||||
unimplemented!()
|
||||
// FIXME: calculate inner types
|
||||
let inner_types =
|
||||
rust_ir::GeneratorWitnessExistential { types: wrap_empty_binders(vec![]) };
|
||||
|
||||
let (parent, _) = self.db.lookup_intern_generator(id.into());
|
||||
// See the comment in `generator_datum()` for unknown types.
|
||||
let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
|
||||
let it = subst
|
||||
.iter(Interner)
|
||||
.map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
|
||||
let inner_types = crate::make_type_and_const_binders(it, inner_types);
|
||||
|
||||
Arc::new(rust_ir::GeneratorWitnessDatum { inner_types })
|
||||
}
|
||||
|
||||
fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
|
||||
|
@ -429,10 +475,15 @@ pub(crate) fn associated_ty_data_query(
|
|||
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
|
||||
let ctx = crate::TyLoweringContext::new(db, &resolver)
|
||||
.with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
|
||||
let pro_ty = TyBuilder::assoc_type_projection(db, type_alias)
|
||||
|
||||
let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
|
||||
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
|
||||
.build();
|
||||
let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst))
|
||||
.fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0)
|
||||
.build();
|
||||
let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner);
|
||||
|
||||
let mut bounds: Vec<_> = type_alias_data
|
||||
.bounds
|
||||
.iter()
|
||||
|
|
|
@ -152,7 +152,7 @@ impl TyExt for Ty {
|
|||
TyKind::FnDef(def, parameters) => {
|
||||
let callable_def = db.lookup_intern_callable_def((*def).into());
|
||||
let sig = db.callable_item_signature(callable_def);
|
||||
Some(sig.substitute(Interner, ¶meters))
|
||||
Some(sig.substitute(Interner, parameters))
|
||||
}
|
||||
TyKind::Closure(.., substs) => {
|
||||
let sig_param = substs.at(Interner, 0).assert_ty_ref(Interner);
|
||||
|
@ -166,6 +166,8 @@ impl TyExt for Ty {
|
|||
let trait_ref = match self.kind(Interner) {
|
||||
// The principal trait bound should be the first element of the bounds. This is an
|
||||
// invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
|
||||
// FIXME: dyn types may not have principal trait and we don't want to return auto trait
|
||||
// here.
|
||||
TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
|
||||
match b.skip_binders() {
|
||||
WhereClause::Implemented(trait_ref) => Some(trait_ref),
|
||||
|
|
|
@ -7,14 +7,17 @@ use std::{
|
|||
|
||||
use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData, IntTy, Scalar};
|
||||
use hir_def::{
|
||||
builtin_type::BuiltinInt,
|
||||
expr::{ArithOp, BinaryOp, Expr, ExprId, Literal, Pat, PatId},
|
||||
path::ModPath,
|
||||
resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs},
|
||||
src::HasChildSource,
|
||||
type_ref::ConstScalar,
|
||||
ConstId, DefWithBodyId,
|
||||
ConstId, DefWithBodyId, EnumVariantId, Lookup,
|
||||
};
|
||||
use la_arena::{Arena, Idx};
|
||||
use la_arena::{Arena, Idx, RawIdx};
|
||||
use stdx::never;
|
||||
use syntax::ast::HasName;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, to_placeholder_idx,
|
||||
|
@ -77,6 +80,7 @@ pub enum ConstEvalError {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ComputedExpr {
|
||||
Literal(Literal),
|
||||
Enum(String, EnumVariantId, Literal),
|
||||
Tuple(Box<[ComputedExpr]>),
|
||||
}
|
||||
|
||||
|
@ -104,6 +108,7 @@ impl Display for ComputedExpr {
|
|||
Literal::String(x) => std::fmt::Debug::fmt(x, f),
|
||||
Literal::ByteString(x) => std::fmt::Debug::fmt(x, f),
|
||||
},
|
||||
ComputedExpr::Enum(name, _, _) => name.fmt(f),
|
||||
ComputedExpr::Tuple(t) => {
|
||||
f.write_char('(')?;
|
||||
for x in &**t {
|
||||
|
@ -148,13 +153,51 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_name(ctx: &mut ConstEvalCtx<'_>, variant: EnumVariantId) -> String {
|
||||
let loc = variant.parent.lookup(ctx.db.upcast());
|
||||
let children = variant.parent.child_source(ctx.db.upcast());
|
||||
let item_tree = loc.id.item_tree(ctx.db.upcast());
|
||||
|
||||
let variant_name = children.value[variant.local_id].name();
|
||||
let enum_name = item_tree[loc.id.value].name.to_string();
|
||||
enum_name + "::" + &variant_name.unwrap().to_string()
|
||||
}
|
||||
|
||||
pub fn eval_const(
|
||||
expr_id: ExprId,
|
||||
ctx: &mut ConstEvalCtx<'_>,
|
||||
) -> Result<ComputedExpr, ConstEvalError> {
|
||||
let u128_to_i128 = |it: u128| -> Result<i128, ConstEvalError> {
|
||||
it.try_into().map_err(|_| ConstEvalError::NotSupported("u128 is too big"))
|
||||
};
|
||||
|
||||
let expr = &ctx.exprs[expr_id];
|
||||
match expr {
|
||||
Expr::Missing => Err(ConstEvalError::IncompleteExpr),
|
||||
Expr::Missing => match ctx.owner {
|
||||
// evaluate the implicit variant index of an enum variant without expression
|
||||
// FIXME: This should return the type of the enum representation
|
||||
DefWithBodyId::VariantId(variant) => {
|
||||
let prev_idx: u32 = variant.local_id.into_raw().into();
|
||||
let prev_idx = prev_idx.checked_sub(1).map(RawIdx::from).map(Idx::from_raw);
|
||||
let value = match prev_idx {
|
||||
Some(local_id) => {
|
||||
let prev_variant = EnumVariantId { local_id, parent: variant.parent };
|
||||
1 + match ctx.db.const_eval_variant(prev_variant)? {
|
||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||
_ => {
|
||||
return Err(ConstEvalError::NotSupported(
|
||||
"Enum can't contain this kind of value",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => 0,
|
||||
};
|
||||
Ok(ComputedExpr::Literal(Literal::Int(value, Some(BuiltinInt::I128))))
|
||||
}
|
||||
_ => Err(ConstEvalError::IncompleteExpr),
|
||||
},
|
||||
Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())),
|
||||
&Expr::UnaryOp { expr, op } => {
|
||||
let ty = &ctx.expr_ty(expr);
|
||||
|
@ -167,9 +210,7 @@ pub fn eval_const(
|
|||
return Ok(ComputedExpr::Literal(Literal::Bool(!b)))
|
||||
}
|
||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => v
|
||||
.try_into()
|
||||
.map_err(|_| ConstEvalError::NotSupported("too big u128"))?,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||
};
|
||||
let r = match ty.kind(Interner) {
|
||||
|
@ -198,9 +239,7 @@ pub fn eval_const(
|
|||
hir_def::expr::UnaryOp::Neg => {
|
||||
let v = match ev {
|
||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => v
|
||||
.try_into()
|
||||
.map_err(|_| ConstEvalError::NotSupported("too big u128"))?,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||
};
|
||||
Ok(ComputedExpr::Literal(Literal::Int(
|
||||
|
@ -219,16 +258,12 @@ pub fn eval_const(
|
|||
let op = op.ok_or(ConstEvalError::IncompleteExpr)?;
|
||||
let v1 = match lhs {
|
||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => {
|
||||
v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))?
|
||||
}
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||
};
|
||||
let v2 = match rhs {
|
||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => {
|
||||
v.try_into().map_err(|_| ConstEvalError::NotSupported("too big u128"))?
|
||||
}
|
||||
ComputedExpr::Literal(Literal::Uint(v, _)) => u128_to_i128(v)?,
|
||||
_ => return Err(ConstEvalError::NotSupported("this kind of operator")),
|
||||
};
|
||||
match op {
|
||||
|
@ -339,9 +374,22 @@ pub fn eval_const(
|
|||
ValueNs::GenericParam(_) => {
|
||||
Err(ConstEvalError::NotSupported("const generic without substitution"))
|
||||
}
|
||||
ValueNs::EnumVariantId(id) => match ctx.db.const_eval_variant(id)? {
|
||||
ComputedExpr::Literal(lit) => {
|
||||
Ok(ComputedExpr::Enum(get_name(ctx, id), id, lit))
|
||||
}
|
||||
_ => Err(ConstEvalError::NotSupported(
|
||||
"Enums can't evalute to anything but numbers",
|
||||
)),
|
||||
},
|
||||
_ => Err(ConstEvalError::NotSupported("path that are not const or local")),
|
||||
}
|
||||
}
|
||||
// FIXME: Handle the cast target
|
||||
&Expr::Cast { expr, .. } => match eval_const(expr, ctx)? {
|
||||
ComputedExpr::Enum(_, _, lit) => Ok(ComputedExpr::Literal(lit)),
|
||||
_ => Err(ConstEvalError::NotSupported("Can't cast these types")),
|
||||
},
|
||||
_ => Err(ConstEvalError::NotSupported("This kind of expression")),
|
||||
}
|
||||
}
|
||||
|
@ -412,7 +460,15 @@ pub(crate) fn const_eval_recover(
|
|||
Err(ConstEvalError::Loop)
|
||||
}
|
||||
|
||||
pub(crate) fn const_eval_query(
|
||||
pub(crate) fn const_eval_variant_recover(
|
||||
_: &dyn HirDatabase,
|
||||
_: &[String],
|
||||
_: &EnumVariantId,
|
||||
) -> Result<ComputedExpr, ConstEvalError> {
|
||||
Err(ConstEvalError::Loop)
|
||||
}
|
||||
|
||||
pub(crate) fn const_eval_variant_query(
|
||||
db: &dyn HirDatabase,
|
||||
const_id: ConstId,
|
||||
) -> Result<ComputedExpr, ConstEvalError> {
|
||||
|
@ -433,6 +489,26 @@ pub(crate) fn const_eval_query(
|
|||
result
|
||||
}
|
||||
|
||||
pub(crate) fn const_eval_query_variant(
|
||||
db: &dyn HirDatabase,
|
||||
variant_id: EnumVariantId,
|
||||
) -> Result<ComputedExpr, ConstEvalError> {
|
||||
let def = variant_id.into();
|
||||
let body = db.body(def);
|
||||
let infer = &db.infer(def);
|
||||
eval_const(
|
||||
body.body_expr,
|
||||
&mut ConstEvalCtx {
|
||||
db,
|
||||
owner: def,
|
||||
exprs: &body.exprs,
|
||||
pats: &body.pats,
|
||||
local_data: HashMap::default(),
|
||||
infer,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn eval_to_const<'a>(
|
||||
expr: Idx<Expr>,
|
||||
mode: ParamLoweringMode,
|
||||
|
|
|
@ -87,6 +87,49 @@ fn consts() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enums() {
|
||||
check_number(
|
||||
r#"
|
||||
enum E {
|
||||
F1 = 1,
|
||||
F2 = 2 * E::F1 as u8,
|
||||
F3 = 3 * E::F2 as u8,
|
||||
}
|
||||
const GOAL: i32 = E::F3 as u8;
|
||||
"#,
|
||||
6,
|
||||
);
|
||||
check_number(
|
||||
r#"
|
||||
enum E { F1 = 1, F2, }
|
||||
const GOAL: i32 = E::F2 as u8;
|
||||
"#,
|
||||
2,
|
||||
);
|
||||
check_number(
|
||||
r#"
|
||||
enum E { F1, }
|
||||
const GOAL: i32 = E::F1 as u8;
|
||||
"#,
|
||||
0,
|
||||
);
|
||||
let r = eval_goal(
|
||||
r#"
|
||||
enum E { A = 1, }
|
||||
const GOAL: E = E::A;
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
match r {
|
||||
ComputedExpr::Enum(name, _, Literal::Uint(val, _)) => {
|
||||
assert_eq!(name, "E::A");
|
||||
assert_eq!(val, 1);
|
||||
}
|
||||
x => panic!("Expected enum but found {:?}", x),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_loop() {
|
||||
check_fail(
|
||||
|
|
|
@ -6,8 +6,8 @@ use std::sync::Arc;
|
|||
use arrayvec::ArrayVec;
|
||||
use base_db::{impl_intern_key, salsa, CrateId, Upcast};
|
||||
use hir_def::{
|
||||
db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, FunctionId,
|
||||
GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
|
||||
db::DefDatabase, expr::ExprId, BlockId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId,
|
||||
FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
|
||||
};
|
||||
use la_arena::ArenaMap;
|
||||
|
||||
|
@ -43,10 +43,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
#[salsa::invoke(crate::lower::const_param_ty_query)]
|
||||
fn const_param_ty(&self, def: ConstParamId) -> Ty;
|
||||
|
||||
#[salsa::invoke(crate::consteval::const_eval_query)]
|
||||
#[salsa::invoke(crate::consteval::const_eval_variant_query)]
|
||||
#[salsa::cycle(crate::consteval::const_eval_recover)]
|
||||
fn const_eval(&self, def: ConstId) -> Result<ComputedExpr, ConstEvalError>;
|
||||
|
||||
#[salsa::invoke(crate::consteval::const_eval_query_variant)]
|
||||
#[salsa::cycle(crate::consteval::const_eval_variant_recover)]
|
||||
fn const_eval_variant(&self, def: EnumVariantId) -> Result<ComputedExpr, ConstEvalError>;
|
||||
|
||||
#[salsa::invoke(crate::lower::impl_trait_query)]
|
||||
fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
|
||||
|
||||
|
@ -116,6 +120,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
|
||||
#[salsa::interned]
|
||||
fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
|
||||
#[salsa::interned]
|
||||
fn intern_generator(&self, id: (DefWithBodyId, ExprId)) -> InternedGeneratorId;
|
||||
|
||||
#[salsa::invoke(chalk_db::associated_ty_data_query)]
|
||||
fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc<chalk_db::AssociatedTyDatum>;
|
||||
|
@ -188,6 +194,9 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
|
|||
DefWithBodyId::ConstId(it) => {
|
||||
db.const_data(it).name.clone().unwrap_or_else(Name::missing).to_string()
|
||||
}
|
||||
DefWithBodyId::VariantId(it) => {
|
||||
db.enum_data(it.parent).variants[it.local_id].name.to_string()
|
||||
}
|
||||
});
|
||||
db.infer_query(def)
|
||||
}
|
||||
|
@ -226,6 +235,10 @@ impl_intern_key!(InternedOpaqueTyId);
|
|||
pub struct InternedClosureId(salsa::InternId);
|
||||
impl_intern_key!(InternedClosureId);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct InternedGeneratorId(salsa::InternId);
|
||||
impl_intern_key!(InternedGeneratorId);
|
||||
|
||||
/// This exists just for Chalk, because Chalk just has a single `FnDefId` where
|
||||
/// we have different IDs for struct and enum variant constructors.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
|
|
|
@ -18,7 +18,9 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
|
|||
|
||||
let is_unsafe = match def {
|
||||
DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(),
|
||||
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
|
||||
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) | DefWithBodyId::VariantId(_) => {
|
||||
false
|
||||
}
|
||||
};
|
||||
if is_unsafe {
|
||||
return res;
|
||||
|
|
|
@ -20,13 +20,14 @@ use hir_def::{
|
|||
};
|
||||
use hir_expand::{hygiene::Hygiene, name::Name};
|
||||
use itertools::Itertools;
|
||||
use smallvec::SmallVec;
|
||||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase,
|
||||
from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
|
||||
mapping::from_chalk,
|
||||
primitive, subst_prefix, to_assoc_type_id,
|
||||
primitive, to_assoc_type_id,
|
||||
utils::{self, generics},
|
||||
AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
|
||||
GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
|
||||
|
@ -221,6 +222,7 @@ pub enum DisplaySourceCodeError {
|
|||
PathNotFound,
|
||||
UnknownType,
|
||||
Closure,
|
||||
Generator,
|
||||
}
|
||||
|
||||
pub enum HirDisplayError {
|
||||
|
@ -504,8 +506,15 @@ impl HirDisplay for Ty {
|
|||
let total_len = parent_params + self_param + type_params + const_params;
|
||||
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
|
||||
if total_len > 0 {
|
||||
// `parameters` are in the order of fn's params (including impl traits),
|
||||
// parent's params (those from enclosing impl or trait, if any).
|
||||
let parameters = parameters.as_slice(Interner);
|
||||
let fn_params_len = self_param + type_params + const_params;
|
||||
let fn_params = parameters.get(..fn_params_len);
|
||||
let parent_params = parameters.get(parameters.len() - parent_params..);
|
||||
let params = parent_params.into_iter().chain(fn_params).flatten();
|
||||
write!(f, "<")?;
|
||||
f.write_joined(¶meters.as_slice(Interner)[..total_len], ", ")?;
|
||||
f.write_joined(params, ", ")?;
|
||||
write!(f, ">")?;
|
||||
}
|
||||
}
|
||||
|
@ -577,9 +586,8 @@ impl HirDisplay for Ty {
|
|||
Some(x) => x,
|
||||
None => return true,
|
||||
};
|
||||
let actual_default = default_parameter
|
||||
.clone()
|
||||
.substitute(Interner, &subst_prefix(parameters, i));
|
||||
let actual_default =
|
||||
default_parameter.clone().substitute(Interner, ¶meters);
|
||||
parameter != &actual_default
|
||||
}
|
||||
let mut default_from = 0;
|
||||
|
@ -783,7 +791,34 @@ impl HirDisplay for Ty {
|
|||
write!(f, "{{unknown}}")?;
|
||||
}
|
||||
TyKind::InferenceVar(..) => write!(f, "_")?,
|
||||
TyKind::Generator(..) => write!(f, "{{generator}}")?,
|
||||
TyKind::Generator(_, subst) => {
|
||||
if f.display_target.is_source_code() {
|
||||
return Err(HirDisplayError::DisplaySourceCodeError(
|
||||
DisplaySourceCodeError::Generator,
|
||||
));
|
||||
}
|
||||
|
||||
let subst = subst.as_slice(Interner);
|
||||
let a: Option<SmallVec<[&Ty; 3]>> = subst
|
||||
.get(subst.len() - 3..)
|
||||
.map(|args| args.iter().map(|arg| arg.ty(Interner)).collect())
|
||||
.flatten();
|
||||
|
||||
if let Some([resume_ty, yield_ty, ret_ty]) = a.as_deref() {
|
||||
write!(f, "|")?;
|
||||
resume_ty.hir_fmt(f)?;
|
||||
write!(f, "|")?;
|
||||
|
||||
write!(f, " yields ")?;
|
||||
yield_ty.hir_fmt(f)?;
|
||||
|
||||
write!(f, " -> ")?;
|
||||
ret_ty.hir_fmt(f)?;
|
||||
} else {
|
||||
// This *should* be unreachable, but fallback just in case.
|
||||
write!(f, "{{generator}}")?;
|
||||
}
|
||||
}
|
||||
TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -19,14 +19,15 @@ use std::sync::Arc;
|
|||
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
||||
use hir_def::{
|
||||
body::Body,
|
||||
builtin_type::BuiltinType,
|
||||
data::{ConstData, StaticData},
|
||||
expr::{BindingAnnotation, ExprId, PatId},
|
||||
lang_item::LangItemTarget,
|
||||
path::{path, Path},
|
||||
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
|
||||
type_ref::TypeRef,
|
||||
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
|
||||
TraitId, TypeAliasId, VariantId,
|
||||
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
|
||||
ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
|
||||
};
|
||||
use hir_expand::name::{name, Name};
|
||||
use itertools::Either;
|
||||
|
@ -67,6 +68,12 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
|
|||
DefWithBodyId::ConstId(c) => ctx.collect_const(&db.const_data(c)),
|
||||
DefWithBodyId::FunctionId(f) => ctx.collect_fn(f),
|
||||
DefWithBodyId::StaticId(s) => ctx.collect_static(&db.static_data(s)),
|
||||
DefWithBodyId::VariantId(v) => {
|
||||
ctx.return_ty = TyBuilder::builtin(match db.enum_data(v.parent).variant_body_type() {
|
||||
Either::Left(builtin) => BuiltinType::Int(builtin),
|
||||
Either::Right(builtin) => BuiltinType::Uint(builtin),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ctx.infer_body();
|
||||
|
@ -332,7 +339,7 @@ pub struct InferenceResult {
|
|||
/// unresolved or missing subpatterns or subpatterns of mismatched types.
|
||||
pub type_of_pat: ArenaMap<PatId, Ty>,
|
||||
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
||||
/// Interned Unknown to return references to.
|
||||
/// Interned common types to return references to.
|
||||
standard_types: InternedStandardTypes,
|
||||
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
||||
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
|
||||
|
@ -412,6 +419,8 @@ pub(crate) struct InferenceContext<'a> {
|
|||
/// closures, but currently this is the only field that will change there,
|
||||
/// so it doesn't make sense.
|
||||
return_ty: Ty,
|
||||
/// The resume type and the yield type, respectively, of the generator being inferred.
|
||||
resume_yield_tys: Option<(Ty, Ty)>,
|
||||
diverges: Diverges,
|
||||
breakables: Vec<BreakableContext>,
|
||||
}
|
||||
|
@ -476,6 +485,7 @@ impl<'a> InferenceContext<'a> {
|
|||
table: unify::InferenceTable::new(db, trait_env.clone()),
|
||||
trait_env,
|
||||
return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
|
||||
resume_yield_tys: None,
|
||||
db,
|
||||
owner,
|
||||
body,
|
||||
|
@ -703,6 +713,8 @@ impl<'a> InferenceContext<'a> {
|
|||
&mut self,
|
||||
inner_ty: Ty,
|
||||
assoc_ty: Option<TypeAliasId>,
|
||||
// FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
|
||||
// handled when we support them.
|
||||
params: &[GenericArg],
|
||||
) -> Ty {
|
||||
match assoc_ty {
|
||||
|
@ -794,7 +806,18 @@ impl<'a> InferenceContext<'a> {
|
|||
self.resolve_variant_on_alias(ty, unresolved, path)
|
||||
}
|
||||
TypeNs::TypeAliasId(it) => {
|
||||
let ty = TyBuilder::def_ty(self.db, it.into())
|
||||
let container = it.lookup(self.db.upcast()).container;
|
||||
let parent_subst = match container {
|
||||
ItemContainerId::TraitId(id) => {
|
||||
let subst = TyBuilder::subst_for_def(self.db, id, None)
|
||||
.fill_with_inference_vars(&mut self.table)
|
||||
.build();
|
||||
Some(subst)
|
||||
}
|
||||
// Type aliases do not exist in impls.
|
||||
_ => None,
|
||||
};
|
||||
let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst)
|
||||
.fill_with_inference_vars(&mut self.table)
|
||||
.build();
|
||||
self.resolve_variant_on_alias(ty, unresolved, path)
|
||||
|
@ -873,6 +896,12 @@ impl<'a> InferenceContext<'a> {
|
|||
fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
|
||||
let path = path![core::iter::IntoIterator];
|
||||
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
||||
self.db.trait_data(trait_).associated_type_by_name(&name![IntoIter])
|
||||
}
|
||||
|
||||
fn resolve_iterator_item(&self) -> Option<TypeAliasId> {
|
||||
let path = path![core::iter::Iterator];
|
||||
let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?;
|
||||
self.db.trait_data(trait_).associated_type_by_name(&name![Item])
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ use crate::{
|
|||
use super::{Expectation, InferenceContext};
|
||||
|
||||
impl InferenceContext<'_> {
|
||||
// This function handles both closures and generators.
|
||||
pub(super) fn deduce_closure_type_from_expectations(
|
||||
&mut self,
|
||||
closure_expr: ExprId,
|
||||
|
@ -27,6 +28,11 @@ impl InferenceContext<'_> {
|
|||
// Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here.
|
||||
let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty);
|
||||
|
||||
// Generators are not Fn* so return early.
|
||||
if matches!(closure_ty.kind(Interner), TyKind::Generator(..)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Deduction based on the expected `dyn Fn` is done separately.
|
||||
if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) {
|
||||
if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) {
|
||||
|
|
|
@ -10,7 +10,10 @@ use chalk_ir::{
|
|||
cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
|
||||
};
|
||||
use hir_def::{
|
||||
expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp},
|
||||
expr::{
|
||||
ArithOp, Array, BinaryOp, ClosureKind, CmpOp, Expr, ExprId, LabelId, Literal, Statement,
|
||||
UnaryOp,
|
||||
},
|
||||
generics::TypeOrConstParamData,
|
||||
path::{GenericArg, GenericArgs},
|
||||
resolver::resolver_for_expr,
|
||||
|
@ -204,8 +207,10 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
&Expr::For { iterable, body, pat, label } => {
|
||||
let iterable_ty = self.infer_expr(iterable, &Expectation::none());
|
||||
let pat_ty =
|
||||
let into_iter_ty =
|
||||
self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
|
||||
let pat_ty =
|
||||
self.resolve_associated_type(into_iter_ty, self.resolve_iterator_item());
|
||||
|
||||
self.infer_pat(pat, &pat_ty, BindingMode::default());
|
||||
self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
|
||||
|
@ -216,7 +221,7 @@ impl<'a> InferenceContext<'a> {
|
|||
self.diverges = Diverges::Maybe;
|
||||
TyBuilder::unit()
|
||||
}
|
||||
Expr::Closure { body, args, ret_type, arg_types } => {
|
||||
Expr::Closure { body, args, ret_type, arg_types, closure_kind } => {
|
||||
assert_eq!(args.len(), arg_types.len());
|
||||
|
||||
let mut sig_tys = Vec::new();
|
||||
|
@ -244,20 +249,40 @@ impl<'a> InferenceContext<'a> {
|
|||
),
|
||||
})
|
||||
.intern(Interner);
|
||||
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
|
||||
let closure_ty =
|
||||
TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
|
||||
.intern(Interner);
|
||||
|
||||
let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) {
|
||||
// FIXME: report error when there are more than 1 parameter.
|
||||
let resume_ty = match sig_tys.first() {
|
||||
// When `sig_tys.len() == 1` the first type is the return type, not the
|
||||
// first parameter type.
|
||||
Some(ty) if sig_tys.len() > 1 => ty.clone(),
|
||||
_ => self.result.standard_types.unit.clone(),
|
||||
};
|
||||
let yield_ty = self.table.new_type_var();
|
||||
|
||||
let subst = TyBuilder::subst_for_generator(self.db, self.owner)
|
||||
.push(resume_ty.clone())
|
||||
.push(yield_ty.clone())
|
||||
.push(ret_ty.clone())
|
||||
.build();
|
||||
|
||||
let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
|
||||
let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
|
||||
|
||||
(generator_ty, Some((resume_ty, yield_ty)))
|
||||
} else {
|
||||
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
|
||||
let closure_ty =
|
||||
TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
|
||||
.intern(Interner);
|
||||
|
||||
(closure_ty, None)
|
||||
};
|
||||
|
||||
// Eagerly try to relate the closure type with the expected
|
||||
// type, otherwise we often won't have enough information to
|
||||
// infer the body.
|
||||
self.deduce_closure_type_from_expectations(
|
||||
tgt_expr,
|
||||
&closure_ty,
|
||||
&sig_ty,
|
||||
expected,
|
||||
);
|
||||
self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
|
||||
|
||||
// Now go through the argument patterns
|
||||
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
|
||||
|
@ -266,6 +291,8 @@ impl<'a> InferenceContext<'a> {
|
|||
|
||||
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
|
||||
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
|
||||
let prev_resume_yield_tys =
|
||||
mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
|
||||
|
||||
self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
|
||||
this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
|
||||
|
@ -273,8 +300,9 @@ impl<'a> InferenceContext<'a> {
|
|||
|
||||
self.diverges = prev_diverges;
|
||||
self.return_ty = prev_ret_ty;
|
||||
self.resume_yield_tys = prev_resume_yield_tys;
|
||||
|
||||
closure_ty
|
||||
ty
|
||||
}
|
||||
Expr::Call { callee, args, .. } => {
|
||||
let callee_ty = self.infer_expr(*callee, &Expectation::none());
|
||||
|
@ -423,11 +451,18 @@ impl<'a> InferenceContext<'a> {
|
|||
TyKind::Never.intern(Interner)
|
||||
}
|
||||
Expr::Yield { expr } => {
|
||||
// FIXME: track yield type for coercion
|
||||
if let Some(expr) = expr {
|
||||
self.infer_expr(*expr, &Expectation::none());
|
||||
if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
|
||||
if let Some(expr) = expr {
|
||||
self.infer_expr_coerce(*expr, &Expectation::has_type(yield_ty));
|
||||
} else {
|
||||
let unit = self.result.standard_types.unit.clone();
|
||||
let _ = self.coerce(Some(tgt_expr), &unit, &yield_ty);
|
||||
}
|
||||
resume_ty
|
||||
} else {
|
||||
// FIXME: report error (yield expr in non-generator)
|
||||
TyKind::Error.intern(Interner)
|
||||
}
|
||||
TyKind::Never.intern(Interner)
|
||||
}
|
||||
Expr::RecordLit { path, fields, spread, .. } => {
|
||||
let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
|
||||
|
@ -952,11 +987,13 @@ impl<'a> InferenceContext<'a> {
|
|||
let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
|
||||
let rhs_ty = self.table.new_type_var();
|
||||
|
||||
let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
|
||||
self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name)
|
||||
let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
|
||||
let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
|
||||
let func = self.db.trait_data(trait_id).method_by_name(&name)?;
|
||||
Some((trait_id, func))
|
||||
});
|
||||
let func = match func {
|
||||
Some(func) => func,
|
||||
let (trait_, func) = match trait_func {
|
||||
Some(it) => it,
|
||||
None => {
|
||||
let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
|
||||
let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
|
||||
|
@ -966,7 +1003,9 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
let subst = TyBuilder::subst_for_def(self.db, func)
|
||||
// HACK: We can use this substitution for the function because the function itself doesn't
|
||||
// have its own generic parameters.
|
||||
let subst = TyBuilder::subst_for_def(self.db, trait_, None)
|
||||
.push(lhs_ty.clone())
|
||||
.push(rhs_ty.clone())
|
||||
.build();
|
||||
|
@ -1245,19 +1284,7 @@ impl<'a> InferenceContext<'a> {
|
|||
assert_eq!(self_params, 0); // method shouldn't have another Self param
|
||||
let total_len = parent_params + type_params + const_params + impl_trait_params;
|
||||
let mut substs = Vec::with_capacity(total_len);
|
||||
// Parent arguments are unknown
|
||||
for (id, param) in def_generics.iter_parent() {
|
||||
match param {
|
||||
TypeOrConstParamData::TypeParamData(_) => {
|
||||
substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
|
||||
}
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
|
||||
substs
|
||||
.push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle provided arguments
|
||||
if let Some(generic_args) = generic_args {
|
||||
// if args are provided, it should be all of them, but we can't rely on that
|
||||
|
@ -1266,7 +1293,7 @@ impl<'a> InferenceContext<'a> {
|
|||
.iter()
|
||||
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
|
||||
.take(type_params + const_params)
|
||||
.zip(def_generics.iter_id().skip(parent_params))
|
||||
.zip(def_generics.iter_id())
|
||||
{
|
||||
if let Some(g) = generic_arg_to_chalk(
|
||||
self.db,
|
||||
|
@ -1290,6 +1317,9 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Handle everything else as unknown. This also handles generic arguments for the method's
|
||||
// parent (impl or trait), which should come after those for the method.
|
||||
for (id, data) in def_generics.iter().skip(substs.len()) {
|
||||
match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => {
|
||||
|
@ -1327,9 +1357,13 @@ impl<'a> InferenceContext<'a> {
|
|||
CallableDefId::FunctionId(f) => {
|
||||
if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
|
||||
// construct a TraitRef
|
||||
let substs = crate::subst_prefix(
|
||||
&*parameters,
|
||||
generics(self.db.upcast(), trait_.into()).len(),
|
||||
let params_len = parameters.len(Interner);
|
||||
let trait_params_len = generics(self.db.upcast(), trait_.into()).len();
|
||||
let substs = Substitution::from_iter(
|
||||
Interner,
|
||||
// The generic parameters for the trait come after those for the
|
||||
// function.
|
||||
¶meters.as_slice(Interner)[params_len - trait_params_len..],
|
||||
);
|
||||
self.push_obligation(
|
||||
TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
|
||||
|
|
|
@ -12,8 +12,8 @@ use crate::{
|
|||
builder::ParamKind,
|
||||
consteval,
|
||||
method_resolution::{self, VisibleFromModule},
|
||||
GenericArgData, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
|
||||
ValueTyDefId,
|
||||
utils::generics,
|
||||
Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
|
||||
};
|
||||
|
||||
use super::{ExprOrPatId, InferenceContext, TraitRef};
|
||||
|
@ -96,17 +96,21 @@ impl<'a> InferenceContext<'a> {
|
|||
ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
|
||||
};
|
||||
|
||||
let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner));
|
||||
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
|
||||
let substs = ctx.substs_from_path(path, typable, true);
|
||||
let mut it = substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned();
|
||||
let ty = TyBuilder::value_ty(self.db, typable)
|
||||
.use_parent_substs(&parent_substs)
|
||||
let substs = substs.as_slice(Interner);
|
||||
let parent_substs = self_subst.or_else(|| {
|
||||
let generics = generics(self.db.upcast(), typable.to_generic_def_id()?);
|
||||
let parent_params_len = generics.parent_generics()?.len();
|
||||
let parent_args = &substs[substs.len() - parent_params_len..];
|
||||
Some(Substitution::from_iter(Interner, parent_args))
|
||||
});
|
||||
let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner));
|
||||
let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned();
|
||||
let ty = TyBuilder::value_ty(self.db, typable, parent_substs)
|
||||
.fill(|x| {
|
||||
it.next().unwrap_or_else(|| match x {
|
||||
ParamKind::Type => {
|
||||
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
||||
}
|
||||
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
|
||||
ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
|
||||
})
|
||||
})
|
||||
|
@ -249,7 +253,7 @@ impl<'a> InferenceContext<'a> {
|
|||
};
|
||||
let substs = match container {
|
||||
ItemContainerId::ImplId(impl_id) => {
|
||||
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
|
||||
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
|
||||
.fill_with_inference_vars(&mut self.table)
|
||||
.build();
|
||||
let impl_self_ty =
|
||||
|
|
|
@ -598,11 +598,14 @@ impl<'a> InferenceTable<'a> {
|
|||
.build();
|
||||
|
||||
let projection = {
|
||||
let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
|
||||
let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
|
||||
if b.remaining() != 2 {
|
||||
return None;
|
||||
}
|
||||
b.push(ty.clone()).push(arg_ty).build()
|
||||
let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
|
||||
|
||||
TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
|
||||
.build()
|
||||
};
|
||||
|
||||
let trait_env = self.trait_env.env.clone();
|
||||
|
|
|
@ -306,7 +306,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
// FIXME we're probably doing something wrong here
|
||||
self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
|
||||
let (
|
||||
parent_params,
|
||||
_parent_params,
|
||||
self_params,
|
||||
list_params,
|
||||
const_params,
|
||||
|
@ -319,7 +319,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
};
|
||||
TyKind::BoundVar(BoundVar::new(
|
||||
self.in_binders,
|
||||
idx as usize + parent_params + self_params + list_params + const_params,
|
||||
idx as usize + self_params + list_params + const_params,
|
||||
))
|
||||
.intern(Interner)
|
||||
}
|
||||
|
@ -499,14 +499,31 @@ impl<'a> TyLoweringContext<'a> {
|
|||
.intern(Interner)
|
||||
}
|
||||
TypeNs::SelfType(impl_id) => {
|
||||
let generics = generics(self.db.upcast(), impl_id.into());
|
||||
let substs = match self.type_param_mode {
|
||||
ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
|
||||
ParamLoweringMode::Variable => {
|
||||
generics.bound_vars_subst(self.db, self.in_binders)
|
||||
let def =
|
||||
self.resolver.generic_def().expect("impl should have generic param scope");
|
||||
let generics = generics(self.db.upcast(), def);
|
||||
|
||||
match self.type_param_mode {
|
||||
ParamLoweringMode::Placeholder => {
|
||||
// `def` can be either impl itself or item within, and we need impl itself
|
||||
// now.
|
||||
let generics = generics.parent_generics().unwrap_or(&generics);
|
||||
let subst = generics.placeholder_subst(self.db);
|
||||
self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
|
||||
}
|
||||
};
|
||||
self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
|
||||
ParamLoweringMode::Variable => {
|
||||
let starting_from = match def {
|
||||
GenericDefId::ImplId(_) => 0,
|
||||
// `def` is an item within impl. We need to substitute `BoundVar`s but
|
||||
// remember that they are for parent (i.e. impl) generic params so they
|
||||
// come after our own params.
|
||||
_ => generics.len_self(),
|
||||
};
|
||||
TyBuilder::impl_self_ty(self.db, impl_id)
|
||||
.fill_with_bound_vars(self.in_binders, starting_from)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeNs::AdtSelfType(adt) => {
|
||||
let generics = generics(self.db.upcast(), adt.into());
|
||||
|
@ -663,40 +680,31 @@ impl<'a> TyLoweringContext<'a> {
|
|||
fn substs_from_path_segment(
|
||||
&self,
|
||||
segment: PathSegment<'_>,
|
||||
def_generic: Option<GenericDefId>,
|
||||
def: Option<GenericDefId>,
|
||||
infer_args: bool,
|
||||
explicit_self_ty: Option<Ty>,
|
||||
) -> Substitution {
|
||||
// Remember that the item's own generic args come before its parent's.
|
||||
let mut substs = Vec::new();
|
||||
let def_generics = if let Some(def) = def_generic {
|
||||
generics(self.db.upcast(), def)
|
||||
let def = if let Some(d) = def {
|
||||
d
|
||||
} else {
|
||||
return Substitution::empty(Interner);
|
||||
};
|
||||
let def_generics = generics(self.db.upcast(), def);
|
||||
let (parent_params, self_params, type_params, const_params, impl_trait_params) =
|
||||
def_generics.provenance_split();
|
||||
let total_len =
|
||||
parent_params + self_params + type_params + const_params + impl_trait_params;
|
||||
let item_len = self_params + type_params + const_params + impl_trait_params;
|
||||
let total_len = parent_params + item_len;
|
||||
|
||||
let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
|
||||
let ty_error = TyKind::Error.intern(Interner).cast(Interner);
|
||||
|
||||
let mut def_generic_iter = def_generics.iter_id();
|
||||
|
||||
for _ in 0..parent_params {
|
||||
if let Some(eid) = def_generic_iter.next() {
|
||||
match eid {
|
||||
Either::Left(_) => substs.push(ty_error.clone()),
|
||||
Either::Right(x) => {
|
||||
substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let fill_self_params = || {
|
||||
for x in explicit_self_ty
|
||||
.into_iter()
|
||||
.map(|x| GenericArgData::Ty(x).intern(Interner))
|
||||
.map(|x| x.cast(Interner))
|
||||
.chain(iter::repeat(ty_error.clone()))
|
||||
.take(self_params)
|
||||
{
|
||||
|
@ -757,37 +765,40 @@ impl<'a> TyLoweringContext<'a> {
|
|||
fill_self_params();
|
||||
}
|
||||
|
||||
// These params include those of parent.
|
||||
let remaining_params: SmallVec<[_; 2]> = def_generic_iter
|
||||
.map(|eid| match eid {
|
||||
Either::Left(_) => ty_error.clone(),
|
||||
Either::Right(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(remaining_params.len() + substs.len(), total_len);
|
||||
|
||||
// handle defaults. In expression or pattern path segments without
|
||||
// explicitly specified type arguments, missing type arguments are inferred
|
||||
// (i.e. defaults aren't used).
|
||||
if !infer_args || had_explicit_args {
|
||||
if let Some(def_generic) = def_generic {
|
||||
let defaults = self.db.generic_defaults(def_generic);
|
||||
assert_eq!(total_len, defaults.len());
|
||||
let defaults = self.db.generic_defaults(def);
|
||||
assert_eq!(total_len, defaults.len());
|
||||
let parent_from = item_len - substs.len();
|
||||
|
||||
for default_ty in defaults.iter().skip(substs.len()) {
|
||||
// each default can depend on the previous parameters
|
||||
let substs_so_far = Substitution::from_iter(Interner, substs.clone());
|
||||
if let Some(_id) = def_generic_iter.next() {
|
||||
substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
|
||||
}
|
||||
}
|
||||
for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() {
|
||||
// each default can depend on the previous parameters
|
||||
let substs_so_far = Substitution::from_iter(
|
||||
Interner,
|
||||
substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()),
|
||||
);
|
||||
substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
|
||||
}
|
||||
|
||||
// Keep parent's params as unknown.
|
||||
let mut remaining_params = remaining_params;
|
||||
substs.extend(remaining_params.drain(parent_from..));
|
||||
} else {
|
||||
substs.extend(remaining_params);
|
||||
}
|
||||
|
||||
// add placeholders for args that were not provided
|
||||
// FIXME: emit diagnostics in contexts where this is not allowed
|
||||
for eid in def_generic_iter {
|
||||
match eid {
|
||||
Either::Left(_) => substs.push(ty_error.clone()),
|
||||
Either::Right(x) => {
|
||||
substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
|
||||
}
|
||||
}
|
||||
}
|
||||
// If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
|
||||
assert_eq!(substs.len(), total_len);
|
||||
|
||||
Substitution::from_iter(Interner, substs)
|
||||
}
|
||||
|
||||
|
@ -981,10 +992,11 @@ impl<'a> TyLoweringContext<'a> {
|
|||
|
||||
fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
|
||||
let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
||||
// INVARIANT: The principal trait bound must come first. Others may be in any order but
|
||||
// should be in the same order for the same set but possibly different order of bounds in
|
||||
// the input.
|
||||
// This invariant is used by `TyExt::dyn_trait()` and chalk.
|
||||
// INVARIANT: The principal trait bound, if present, must come first. Others may be in any
|
||||
// order but should be in the same order for the same set but possibly different order of
|
||||
// bounds in the input.
|
||||
// INVARIANT: If this function returns `DynTy`, there should be at least one trait bound.
|
||||
// These invariants are utilized by `TyExt::dyn_trait()` and chalk.
|
||||
let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
|
||||
let mut bounds: Vec<_> = bounds
|
||||
.iter()
|
||||
|
@ -1035,6 +1047,12 @@ impl<'a> TyLoweringContext<'a> {
|
|||
return None;
|
||||
}
|
||||
|
||||
if bounds.first().and_then(|b| b.trait_id()).is_none() {
|
||||
// When there's no trait bound, that's an error. This happens when the trait refs
|
||||
// are unresolved.
|
||||
return None;
|
||||
}
|
||||
|
||||
// As multiple occurrences of the same auto traits *are* permitted, we dedulicate the
|
||||
// bounds. We shouldn't have repeated elements besides auto traits at this point.
|
||||
bounds.dedup();
|
||||
|
@ -1046,7 +1064,8 @@ impl<'a> TyLoweringContext<'a> {
|
|||
let bounds = crate::make_single_type_binders(bounds);
|
||||
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
|
||||
} else {
|
||||
// FIXME: report error (additional non-auto traits or associated type rebound)
|
||||
// FIXME: report error
|
||||
// (additional non-auto traits, associated type rebound, or no resolved trait)
|
||||
TyKind::Error.intern(Interner)
|
||||
}
|
||||
}
|
||||
|
@ -1139,11 +1158,28 @@ fn named_associated_type_shorthand_candidates<R>(
|
|||
};
|
||||
|
||||
match res {
|
||||
TypeNs::SelfType(impl_id) => search(
|
||||
TypeNs::SelfType(impl_id) => {
|
||||
// we're _in_ the impl -- the binders get added back later. Correct,
|
||||
// but it would be nice to make this more explicit
|
||||
db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
|
||||
),
|
||||
let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0;
|
||||
|
||||
let impl_id_as_generic_def: GenericDefId = impl_id.into();
|
||||
if impl_id_as_generic_def != def {
|
||||
// `trait_ref` contains `BoundVar`s bound by impl's `Binders`, but here we need
|
||||
// `BoundVar`s from `def`'s point of view.
|
||||
// FIXME: A `HirDatabase` query may be handy if this process is needed in more
|
||||
// places. It'd be almost identical as `impl_trait_query` where `resolver` would be
|
||||
// of `def` instead of `impl_id`.
|
||||
let starting_idx = generics(db.upcast(), def).len_self();
|
||||
let subst = TyBuilder::subst_for_def(db, impl_id, None)
|
||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
|
||||
.build();
|
||||
let trait_ref = subst.apply(trait_ref, Interner);
|
||||
search(trait_ref)
|
||||
} else {
|
||||
search(trait_ref)
|
||||
}
|
||||
}
|
||||
TypeNs::GenericParam(param_id) => {
|
||||
let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
|
||||
let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
|
||||
|
@ -1160,10 +1196,18 @@ fn named_associated_type_shorthand_candidates<R>(
|
|||
}
|
||||
// Handle `Self::Type` referring to own associated type in trait definitions
|
||||
if let GenericDefId::TraitId(trait_id) = param_id.parent() {
|
||||
let generics = generics(db.upcast(), trait_id.into());
|
||||
if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
|
||||
let trait_generics = generics(db.upcast(), trait_id.into());
|
||||
if trait_generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
|
||||
let def_generics = generics(db.upcast(), def);
|
||||
let starting_idx = match def {
|
||||
GenericDefId::TraitId(_) => 0,
|
||||
// `def` is an item within trait. We need to substitute `BoundVar`s but
|
||||
// remember that they are for parent (i.e. trait) generic params so they
|
||||
// come after our own params.
|
||||
_ => def_generics.len_self(),
|
||||
};
|
||||
let trait_ref = TyBuilder::trait_ref(db, trait_id)
|
||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
|
||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
|
||||
.build();
|
||||
return search(trait_ref);
|
||||
}
|
||||
|
@ -1405,6 +1449,7 @@ pub(crate) fn generic_defaults_query(
|
|||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let generic_params = generics(db.upcast(), def);
|
||||
let parent_start_idx = generic_params.len_self();
|
||||
|
||||
let defaults = generic_params
|
||||
.iter()
|
||||
|
@ -1417,19 +1462,17 @@ pub(crate) fn generic_defaults_query(
|
|||
let val = unknown_const_as_generic(
|
||||
db.const_param_ty(ConstParamId::from_unchecked(id)),
|
||||
);
|
||||
return crate::make_binders_with_count(db, idx, &generic_params, val);
|
||||
return make_binders(db, &generic_params, val);
|
||||
}
|
||||
};
|
||||
let mut ty =
|
||||
p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
|
||||
|
||||
// Each default can only refer to previous parameters.
|
||||
// type variable default referring to parameter coming
|
||||
// after it. This is forbidden (FIXME: report
|
||||
// diagnostic)
|
||||
ty = fallback_bound_vars(ty, idx);
|
||||
let val = GenericArgData::Ty(ty).intern(Interner);
|
||||
crate::make_binders_with_count(db, idx, &generic_params, val)
|
||||
// Type variable default referring to parameter coming
|
||||
// after it is forbidden (FIXME: report diagnostic)
|
||||
ty = fallback_bound_vars(ty, idx, parent_start_idx);
|
||||
crate::make_binders(db, &generic_params, ty.cast(Interner))
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -1446,15 +1489,14 @@ pub(crate) fn generic_defaults_recover(
|
|||
// we still need one default per parameter
|
||||
let defaults = generic_params
|
||||
.iter_id()
|
||||
.enumerate()
|
||||
.map(|(count, id)| {
|
||||
.map(|id| {
|
||||
let val = match id {
|
||||
itertools::Either::Left(_) => {
|
||||
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
||||
}
|
||||
itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
|
||||
};
|
||||
crate::make_binders_with_count(db, count, &generic_params, val)
|
||||
crate::make_binders(db, &generic_params, val)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -1633,6 +1675,19 @@ pub enum ValueTyDefId {
|
|||
}
|
||||
impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
|
||||
|
||||
impl ValueTyDefId {
|
||||
pub(crate) fn to_generic_def_id(self) -> Option<GenericDefId> {
|
||||
match self {
|
||||
Self::FunctionId(id) => Some(id.into()),
|
||||
Self::StructId(id) => Some(id.into()),
|
||||
Self::UnionId(id) => Some(id.into()),
|
||||
Self::EnumVariantId(var) => Some(var.into()),
|
||||
Self::ConstId(id) => Some(id.into()),
|
||||
Self::StaticId(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the declared type of an item. This depends on the namespace; e.g. for
|
||||
/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
|
||||
/// the constructor function `(usize) -> Foo` which lives in the values
|
||||
|
@ -1816,26 +1871,48 @@ pub(crate) fn const_or_path_to_chalk(
|
|||
}
|
||||
}
|
||||
|
||||
/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
|
||||
/// num_vars_to_keep) by `TyKind::Unknown`.
|
||||
/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
|
||||
/// parameter whose index is `param_index`. A `BoundVar` is free when it is or (syntactically)
|
||||
/// appears after the generic parameter of `param_index`.
|
||||
fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
|
||||
s: T,
|
||||
num_vars_to_keep: usize,
|
||||
param_index: usize,
|
||||
parent_start: usize,
|
||||
) -> T {
|
||||
// Keep in mind that parent generic parameters, if any, come *after* those of the item in
|
||||
// question. In the diagrams below, `c*` and `p*` represent generic parameters of the item and
|
||||
// its parent respectively.
|
||||
let is_allowed = |index| {
|
||||
if param_index < parent_start {
|
||||
// The parameter of `param_index` is one from the item in question. Any parent generic
|
||||
// parameters or the item's generic parameters that come before `param_index` is
|
||||
// allowed.
|
||||
// [c1, .., cj, .., ck, p1, .., pl] where cj is `param_index`
|
||||
// ^^^^^^ ^^^^^^^^^^ these are allowed
|
||||
!(param_index..parent_start).contains(&index)
|
||||
} else {
|
||||
// The parameter of `param_index` is one from the parent generics. Only parent generic
|
||||
// parameters that come before `param_index` are allowed.
|
||||
// [c1, .., ck, p1, .., pj, .., pl] where pj is `param_index`
|
||||
// ^^^^^^ these are allowed
|
||||
(parent_start..param_index).contains(&index)
|
||||
}
|
||||
};
|
||||
|
||||
crate::fold_free_vars(
|
||||
s,
|
||||
|bound, binders| {
|
||||
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
||||
TyKind::Error.intern(Interner)
|
||||
} else {
|
||||
if bound.index_if_innermost().map_or(true, is_allowed) {
|
||||
bound.shifted_in_from(binders).to_ty(Interner)
|
||||
} else {
|
||||
TyKind::Error.intern(Interner)
|
||||
}
|
||||
},
|
||||
|ty, bound, binders| {
|
||||
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
||||
unknown_const(ty.clone())
|
||||
} else {
|
||||
if bound.index_if_innermost().map_or(true, is_allowed) {
|
||||
bound.shifted_in_from(binders).to_const(Interner, ty)
|
||||
} else {
|
||||
unknown_const(ty.clone())
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
@ -103,6 +103,18 @@ impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<chalk_ir::GeneratorId<Interner>> for crate::db::InternedGeneratorId {
|
||||
fn from(id: chalk_ir::GeneratorId<Interner>) -> Self {
|
||||
Self::from_intern_id(id.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::db::InternedGeneratorId> for chalk_ir::GeneratorId<Interner> {
|
||||
fn from(id: crate::db::InternedGeneratorId) -> Self {
|
||||
chalk_ir::GeneratorId(id.as_intern_id())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId {
|
||||
chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id))
|
||||
}
|
||||
|
|
|
@ -654,7 +654,7 @@ fn find_matching_impl(
|
|||
let r = table.run_in_snapshot(|table| {
|
||||
let impl_data = db.impl_data(impl_);
|
||||
let substs =
|
||||
TyBuilder::subst_for_def(db, impl_).fill_with_inference_vars(table).build();
|
||||
TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
|
||||
let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
|
||||
|
||||
table
|
||||
|
@ -1147,10 +1147,9 @@ fn is_valid_candidate(
|
|||
}));
|
||||
if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
|
||||
let self_ty_matches = table.run_in_snapshot(|table| {
|
||||
let subst =
|
||||
TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build();
|
||||
let expected_self_ty =
|
||||
subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner);
|
||||
let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
|
||||
.fill_with_inference_vars(table)
|
||||
.build();
|
||||
table.unify(&expected_self_ty, &self_ty)
|
||||
});
|
||||
if !self_ty_matches {
|
||||
|
@ -1186,31 +1185,26 @@ fn is_valid_fn_candidate(
|
|||
|
||||
table.run_in_snapshot(|table| {
|
||||
let container = fn_id.lookup(db.upcast()).container;
|
||||
let impl_subst = match container {
|
||||
let (impl_subst, expect_self_ty) = match container {
|
||||
ItemContainerId::ImplId(it) => {
|
||||
TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
|
||||
let subst =
|
||||
TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
|
||||
let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
|
||||
(subst, self_ty)
|
||||
}
|
||||
ItemContainerId::TraitId(it) => {
|
||||
TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
|
||||
let subst =
|
||||
TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
|
||||
let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
|
||||
(subst, self_ty)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let fn_subst = TyBuilder::subst_for_def(db, fn_id)
|
||||
.use_parent_substs(&impl_subst)
|
||||
let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
|
||||
.fill_with_inference_vars(table)
|
||||
.build();
|
||||
|
||||
let expect_self_ty = match container {
|
||||
ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
|
||||
ItemContainerId::ImplId(impl_id) => {
|
||||
fn_subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
|
||||
}
|
||||
// We should only get called for associated items (impl/trait)
|
||||
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
check_that!(table.unify(&expect_self_ty, self_ty));
|
||||
|
||||
if let Some(receiver_ty) = receiver_ty {
|
||||
|
|
|
@ -16,7 +16,7 @@ use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt};
|
|||
use expect_test::Expect;
|
||||
use hir_def::{
|
||||
body::{Body, BodySourceMap, SyntheticSyntax},
|
||||
db::DefDatabase,
|
||||
db::{DefDatabase, InternDatabase},
|
||||
expr::{ExprId, PatId},
|
||||
item_scope::ItemScope,
|
||||
nameres::DefMap,
|
||||
|
@ -135,6 +135,10 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
|
|||
let loc = it.lookup(&db);
|
||||
loc.source(&db).value.syntax().text_range().start()
|
||||
}
|
||||
DefWithBodyId::VariantId(it) => {
|
||||
let loc = db.lookup_intern_enum(it.parent);
|
||||
loc.source(&db).value.syntax().text_range().start()
|
||||
}
|
||||
});
|
||||
let mut unexpected_type_mismatches = String::new();
|
||||
for def in defs {
|
||||
|
@ -388,6 +392,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
|||
let loc = it.lookup(&db);
|
||||
loc.source(&db).value.syntax().text_range().start()
|
||||
}
|
||||
DefWithBodyId::VariantId(it) => {
|
||||
let loc = db.lookup_intern_enum(it.parent);
|
||||
loc.source(&db).value.syntax().text_range().start()
|
||||
}
|
||||
});
|
||||
for def in defs {
|
||||
let (_body, source_map) = db.body_with_source_map(def);
|
||||
|
@ -453,6 +461,18 @@ fn visit_module(
|
|||
let body = db.body(def);
|
||||
visit_body(db, &body, cb);
|
||||
}
|
||||
ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
|
||||
db.enum_data(it)
|
||||
.variants
|
||||
.iter()
|
||||
.map(|(id, _)| hir_def::EnumVariantId { parent: it, local_id: id })
|
||||
.for_each(|it| {
|
||||
let def = it.into();
|
||||
cb(def);
|
||||
let body = db.body(def);
|
||||
visit_body(db, &body, cb);
|
||||
});
|
||||
}
|
||||
ModuleDefId::TraitId(it) => {
|
||||
let trait_data = db.trait_data(it);
|
||||
for &(_, item) in trait_data.items.iter() {
|
||||
|
|
|
@ -294,6 +294,24 @@ fn foo() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generator_yield_return_coerce() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
fn test() {
|
||||
let g = || {
|
||||
yield &1u32;
|
||||
yield &&1u32;
|
||||
if true {
|
||||
return &1u32;
|
||||
}
|
||||
&&1u32
|
||||
};
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assign_coerce() {
|
||||
check_no_mismatches(
|
||||
|
|
|
@ -1488,7 +1488,6 @@ fn regression_11688_4() {
|
|||
|
||||
#[test]
|
||||
fn gat_crash_1() {
|
||||
cov_mark::check!(ignore_gats);
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
trait ATrait {}
|
||||
|
@ -1527,30 +1526,22 @@ unsafe impl Storage for InlineStorage {
|
|||
|
||||
#[test]
|
||||
fn gat_crash_3() {
|
||||
// FIXME: This test currently crashes rust analyzer in a debug build but not in a
|
||||
// release build (i.e. for the user). With the assumption that tests will always be run
|
||||
// in debug mode, we catch the unwind and expect that it panicked. See the
|
||||
// [`crate::utils::generics`] function for more information.
|
||||
cov_mark::check!(ignore_gats);
|
||||
std::panic::catch_unwind(|| {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
trait Collection {
|
||||
type Item;
|
||||
type Member<T>: Collection<Item = T>;
|
||||
fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
|
||||
type Item;
|
||||
type Member<T>: Collection<Item = T>;
|
||||
fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
|
||||
}
|
||||
struct ConstGen<T, const N: usize> {
|
||||
data: [T; N],
|
||||
data: [T; N],
|
||||
}
|
||||
impl<T, const N: usize> Collection for ConstGen<T, N> {
|
||||
type Item = T;
|
||||
type Member<U> = ConstGen<U, N>;
|
||||
type Item = T;
|
||||
type Member<U> = ConstGen<U, N>;
|
||||
}
|
||||
"#,
|
||||
);
|
||||
})
|
||||
.expect_err("must panic");
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1691,3 +1682,28 @@ fn macrostmts() -> u8 {
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dyn_with_unresolved_trait() {
|
||||
check_types(
|
||||
r#"
|
||||
fn foo(a: &dyn DoesNotExist) {
|
||||
a.bar();
|
||||
//^&{unknown}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn self_assoc_with_const_generics_crash() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
trait Trait { type Item; }
|
||||
impl<T, const N: usize> Trait for [T; N] {
|
||||
type Item = ();
|
||||
fn f<U>(_: Self::Item) {}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1693,16 +1693,16 @@ fn infer_type_param() {
|
|||
fn infer_const() {
|
||||
check_infer(
|
||||
r#"
|
||||
struct Foo;
|
||||
impl Foo { const ASSOC_CONST: u32 = 0; }
|
||||
const GLOBAL_CONST: u32 = 101;
|
||||
fn test() {
|
||||
const LOCAL_CONST: u32 = 99;
|
||||
let x = LOCAL_CONST;
|
||||
let z = GLOBAL_CONST;
|
||||
let id = Foo::ASSOC_CONST;
|
||||
}
|
||||
"#,
|
||||
struct Foo;
|
||||
impl Foo { const ASSOC_CONST: u32 = 0; }
|
||||
const GLOBAL_CONST: u32 = 101;
|
||||
fn test() {
|
||||
const LOCAL_CONST: u32 = 99;
|
||||
let x = LOCAL_CONST;
|
||||
let z = GLOBAL_CONST;
|
||||
let id = Foo::ASSOC_CONST;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
48..49 '0': u32
|
||||
79..82 '101': u32
|
||||
|
@ -1722,17 +1722,17 @@ fn infer_const() {
|
|||
fn infer_static() {
|
||||
check_infer(
|
||||
r#"
|
||||
static GLOBAL_STATIC: u32 = 101;
|
||||
static mut GLOBAL_STATIC_MUT: u32 = 101;
|
||||
fn test() {
|
||||
static LOCAL_STATIC: u32 = 99;
|
||||
static mut LOCAL_STATIC_MUT: u32 = 99;
|
||||
let x = LOCAL_STATIC;
|
||||
let y = LOCAL_STATIC_MUT;
|
||||
let z = GLOBAL_STATIC;
|
||||
let w = GLOBAL_STATIC_MUT;
|
||||
}
|
||||
"#,
|
||||
static GLOBAL_STATIC: u32 = 101;
|
||||
static mut GLOBAL_STATIC_MUT: u32 = 101;
|
||||
fn test() {
|
||||
static LOCAL_STATIC: u32 = 99;
|
||||
static mut LOCAL_STATIC_MUT: u32 = 99;
|
||||
let x = LOCAL_STATIC;
|
||||
let y = LOCAL_STATIC_MUT;
|
||||
let z = GLOBAL_STATIC;
|
||||
let w = GLOBAL_STATIC_MUT;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
28..31 '101': u32
|
||||
69..72 '101': u32
|
||||
|
@ -1751,6 +1751,41 @@ fn infer_static() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_enum_variant() {
|
||||
check_infer(
|
||||
r#"
|
||||
enum Foo {
|
||||
A = 15,
|
||||
B = Foo::A as isize + 1
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
19..21 '15': isize
|
||||
31..37 'Foo::A': Foo
|
||||
31..46 'Foo::A as isize': isize
|
||||
31..50 'Foo::A...ze + 1': isize
|
||||
49..50 '1': isize
|
||||
"#]],
|
||||
);
|
||||
check_infer(
|
||||
r#"
|
||||
#[repr(u32)]
|
||||
enum Foo {
|
||||
A = 15,
|
||||
B = Foo::A as u32 + 1
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
32..34 '15': u32
|
||||
44..50 'Foo::A': Foo
|
||||
44..57 'Foo::A as u32': u32
|
||||
44..61 'Foo::A...32 + 1': u32
|
||||
60..61 '1': u32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shadowing_primitive() {
|
||||
check_types(
|
||||
|
@ -1917,6 +1952,88 @@ fn closure_return_inferred() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generator_types_inferred() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: generator, deref
|
||||
use core::ops::{Generator, GeneratorState};
|
||||
use core::pin::Pin;
|
||||
|
||||
fn f(v: i64) {}
|
||||
fn test() {
|
||||
let mut g = |r| {
|
||||
let a = yield 0;
|
||||
let a = yield 1;
|
||||
let a = yield 2;
|
||||
"return value"
|
||||
};
|
||||
|
||||
match Pin::new(&mut g).resume(0usize) {
|
||||
GeneratorState::Yielded(y) => { f(y); }
|
||||
GeneratorState::Complete(r) => {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
70..71 'v': i64
|
||||
78..80 '{}': ()
|
||||
91..362 '{ ... } }': ()
|
||||
101..106 'mut g': |usize| yields i64 -> &str
|
||||
109..218 '|r| { ... }': |usize| yields i64 -> &str
|
||||
110..111 'r': usize
|
||||
113..218 '{ ... }': &str
|
||||
127..128 'a': usize
|
||||
131..138 'yield 0': usize
|
||||
137..138 '0': i64
|
||||
152..153 'a': usize
|
||||
156..163 'yield 1': usize
|
||||
162..163 '1': i64
|
||||
177..178 'a': usize
|
||||
181..188 'yield 2': usize
|
||||
187..188 '2': i64
|
||||
198..212 '"return value"': &str
|
||||
225..360 'match ... }': ()
|
||||
231..239 'Pin::new': fn new<&mut |usize| yields i64 -> &str>(&mut |usize| yields i64 -> &str) -> Pin<&mut |usize| yields i64 -> &str>
|
||||
231..247 'Pin::n...mut g)': Pin<&mut |usize| yields i64 -> &str>
|
||||
231..262 'Pin::n...usize)': GeneratorState<i64, &str>
|
||||
240..246 '&mut g': &mut |usize| yields i64 -> &str
|
||||
245..246 'g': |usize| yields i64 -> &str
|
||||
255..261 '0usize': usize
|
||||
273..299 'Genera...ded(y)': GeneratorState<i64, &str>
|
||||
297..298 'y': i64
|
||||
303..312 '{ f(y); }': ()
|
||||
305..306 'f': fn f(i64)
|
||||
305..309 'f(y)': ()
|
||||
307..308 'y': i64
|
||||
321..348 'Genera...ete(r)': GeneratorState<i64, &str>
|
||||
346..347 'r': &str
|
||||
352..354 '{}': ()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generator_resume_yield_return_unit() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
//- minicore: generator, deref
|
||||
use core::ops::{Generator, GeneratorState};
|
||||
use core::pin::Pin;
|
||||
fn test() {
|
||||
let mut g = || {
|
||||
let () = yield;
|
||||
};
|
||||
|
||||
match Pin::new(&mut g).resume(()) {
|
||||
GeneratorState::Yielded(()) => {}
|
||||
GeneratorState::Complete(()) => {}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_pointer_return() {
|
||||
check_infer(
|
||||
|
|
|
@ -279,6 +279,10 @@ fn test() {
|
|||
pub mod iter {
|
||||
pub trait IntoIterator {
|
||||
type Item;
|
||||
type IntoIter: Iterator<Item = Self::Item>;
|
||||
}
|
||||
pub trait Iterator {
|
||||
type Item;
|
||||
}
|
||||
}
|
||||
pub mod prelude {
|
||||
|
@ -297,7 +301,13 @@ pub mod collections {
|
|||
}
|
||||
|
||||
impl<T> IntoIterator for Vec<T> {
|
||||
type Item=T;
|
||||
type Item = T;
|
||||
type IntoIter = IntoIter<T>;
|
||||
}
|
||||
|
||||
struct IntoIter<T> {}
|
||||
impl<T> Iterator for IntoIter<T> {
|
||||
type Item = T;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
use std::iter;
|
||||
|
||||
use base_db::CrateId;
|
||||
use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
|
||||
use chalk_ir::{cast::Cast, fold::Shift, BoundVar, DebruijnIndex};
|
||||
use hir_def::{
|
||||
db::DefDatabase,
|
||||
generics::{
|
||||
|
@ -24,8 +24,7 @@ use smallvec::{smallvec, SmallVec};
|
|||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, ChalkTraitId, ConstData, ConstValue, GenericArgData, Interner, Substitution,
|
||||
TraitRef, TraitRefExt, TyKind, WhereClause,
|
||||
db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, WhereClause,
|
||||
};
|
||||
|
||||
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
|
||||
|
@ -174,31 +173,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
|
|||
|
||||
pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
|
||||
let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
|
||||
if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) {
|
||||
let params = db.generic_params(def);
|
||||
let parent_params = &parent_generics.as_ref().unwrap().params;
|
||||
let has_consts =
|
||||
params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
|
||||
let parent_has_consts =
|
||||
parent_params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
|
||||
return if has_consts || parent_has_consts {
|
||||
// XXX: treat const generic associated types as not existing to avoid crashes
|
||||
// (#11769)
|
||||
//
|
||||
// Note: Also crashes when the parent has const generics (also even if the GAT
|
||||
// doesn't use them), see `tests::regression::gat_crash_3` for an example.
|
||||
// Avoids that by disabling GATs when the parent (i.e. `impl` block) has
|
||||
// const generics (#12193).
|
||||
//
|
||||
// Chalk expects the inner associated type's parameters to come
|
||||
// *before*, not after the trait's generics as we've always done it.
|
||||
// Adapting to this requires a larger refactoring
|
||||
cov_mark::hit!(ignore_gats);
|
||||
Generics { def, params: Interned::new(Default::default()), parent_generics }
|
||||
} else {
|
||||
Generics { def, params, parent_generics }
|
||||
};
|
||||
}
|
||||
Generics { def, params: db.generic_params(def), parent_generics }
|
||||
}
|
||||
|
||||
|
@ -221,23 +195,30 @@ impl Generics {
|
|||
})
|
||||
}
|
||||
|
||||
/// Iterator over types and const params of parent, then self.
|
||||
/// Iterator over types and const params of self, then parent.
|
||||
pub(crate) fn iter<'a>(
|
||||
&'a self,
|
||||
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||
let to_toc_id = |it: &'a Generics| {
|
||||
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
|
||||
};
|
||||
self.parent_generics()
|
||||
.into_iter()
|
||||
.flat_map(move |it| it.params.iter().map(to_toc_id(it)))
|
||||
.chain(self.params.iter().map(to_toc_id(self)))
|
||||
self.params.iter().map(to_toc_id(self)).chain(self.iter_parent())
|
||||
}
|
||||
|
||||
/// Iterate over types and const params without parent params.
|
||||
pub(crate) fn iter_self<'a>(
|
||||
&'a self,
|
||||
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||
let to_toc_id = |it: &'a Generics| {
|
||||
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
|
||||
};
|
||||
self.params.iter().map(to_toc_id(self))
|
||||
}
|
||||
|
||||
/// Iterator over types and const params of parent.
|
||||
pub(crate) fn iter_parent<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||
self.parent_generics().into_iter().flat_map(|it| {
|
||||
let to_toc_id =
|
||||
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p);
|
||||
|
@ -245,12 +226,18 @@ impl Generics {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns total number of generic parameters in scope, including those from parent.
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
let parent = self.parent_generics().map_or(0, Generics::len);
|
||||
let child = self.params.type_or_consts.len();
|
||||
parent + child
|
||||
}
|
||||
|
||||
/// Returns numbers of generic parameters excluding those from parent.
|
||||
pub(crate) fn len_self(&self) -> usize {
|
||||
self.params.type_or_consts.len()
|
||||
}
|
||||
|
||||
/// (parent total, self param, type param list, const param list, impl trait)
|
||||
pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
|
||||
let ty_iter = || self.params.iter().filter_map(|x| x.1.type_param());
|
||||
|
@ -275,15 +262,17 @@ impl Generics {
|
|||
if param.parent == self.def {
|
||||
let (idx, (_local_id, data)) =
|
||||
self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
|
||||
let parent_len = self.parent_generics().map_or(0, Generics::len);
|
||||
Some((parent_len + idx, data))
|
||||
Some((idx, data))
|
||||
} else {
|
||||
self.parent_generics().and_then(|g| g.find_param(param))
|
||||
self.parent_generics()
|
||||
.and_then(|g| g.find_param(param))
|
||||
// Remember that parent parameters come after parameters for self.
|
||||
.map(|(idx, data)| (self.len_self() + idx, data))
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_generics(&self) -> Option<&Generics> {
|
||||
self.parent_generics.as_ref().map(|it| &**it)
|
||||
pub(crate) fn parent_generics(&self) -> Option<&Generics> {
|
||||
self.parent_generics.as_deref()
|
||||
}
|
||||
|
||||
/// Returns a Substitution that replaces each parameter by a bound variable.
|
||||
|
@ -295,18 +284,10 @@ impl Generics {
|
|||
Substitution::from_iter(
|
||||
Interner,
|
||||
self.iter_id().enumerate().map(|(idx, id)| match id {
|
||||
Either::Left(_) => GenericArgData::Ty(
|
||||
TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
Either::Right(id) => GenericArgData::Const(
|
||||
ConstData {
|
||||
value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
|
||||
ty: db.const_param_ty(id),
|
||||
}
|
||||
.intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
Either::Left(_) => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
|
||||
Either::Right(id) => BoundVar::new(debruijn, idx)
|
||||
.to_const(Interner, db.const_param_ty(id))
|
||||
.cast(Interner),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
@ -316,18 +297,12 @@ impl Generics {
|
|||
Substitution::from_iter(
|
||||
Interner,
|
||||
self.iter_id().map(|id| match id {
|
||||
Either::Left(id) => GenericArgData::Ty(
|
||||
TyKind::Placeholder(crate::to_placeholder_idx(db, id.into())).intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
Either::Right(id) => GenericArgData::Const(
|
||||
ConstData {
|
||||
value: ConstValue::Placeholder(crate::to_placeholder_idx(db, id.into())),
|
||||
ty: db.const_param_ty(id),
|
||||
}
|
||||
.intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
Either::Left(id) => {
|
||||
crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
|
||||
}
|
||||
Either::Right(id) => crate::to_placeholder_idx(db, id.into())
|
||||
.to_const(Interner, db.const_param_ty(id))
|
||||
.cast(Interner),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue