8419: Move hir_ty to Chalk IR r=flodiebold a=flodiebold

Closes #8313.

There's some further cleanups to do:
 - we're still using our `TypeWalk` in lots of places (not for mutating/folding though, just for walking)
 - we're still using our own canonicalization and unification and our `InferenceTable`
 - ~`ToChalk` still exists and gets called, it's just the identity in most cases now (I'll probably clean those up before merging this)~

8423: Bump lsp-types and syn r=kjeremy a=kjeremy

This lsp-types now supports a default InsertTextMode for completion and a per-completion item commit_characters

Co-authored-by: Florian Diebold <flodiebold@gmail.com>
Co-authored-by: kjeremy <kjeremy@gmail.com>
This commit is contained in:
bors[bot] 2021-04-08 15:00:53 +00:00 committed by GitHub
commit 72ad5cbe16
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 345 additions and 1551 deletions

8
Cargo.lock generated
View file

@ -852,9 +852,9 @@ dependencies = [
[[package]]
name = "lsp-types"
version = "0.88.0"
version = "0.89.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8e8e042772e4e10b3785822f63c82399d0dd233825de44d2596f7fa86e023e0"
checksum = "07731ecd4ee0654728359a5b95e2a254c857876c04b85225496a35d60345daa7"
dependencies = [
"bitflags",
"serde",
@ -1577,9 +1577,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.68"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87"
checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
dependencies = [
"proc-macro2",
"quote",

View file

@ -1903,7 +1903,9 @@ impl Type {
| TyKind::Dyn(_)
| TyKind::Function(_)
| TyKind::Alias(_)
| TyKind::Foreign(_) => false,
| TyKind::Foreign(_)
| TyKind::Generator(..)
| TyKind::GeneratorWitness(..) => false,
}
}
}

View file

@ -4,6 +4,7 @@ use std::iter;
use chalk_ir::{
cast::{Cast, CastTo, Caster},
fold::Fold,
interner::HasInterner,
AdtId, BoundVar, DebruijnIndex, Safety, Scalar,
};
@ -13,7 +14,7 @@ use smallvec::SmallVec;
use crate::{
db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders,
CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution,
TraitRef, Ty, TyDefId, TyExt, TyKind, TypeWalk, ValueTyDefId,
TraitRef, Ty, TyDefId, TyExt, TyKind, ValueTyDefId,
};
/// This is a builder for `Ty` or anything that needs a `Substitution`.
@ -32,8 +33,7 @@ impl<D> TyBuilder<D> {
fn build_internal(self) -> (D, Substitution) {
assert_eq!(self.vec.len(), self.param_count);
// FIXME: would be good to have a way to construct a chalk_ir::Substitution from the interned form
let subst = Substitution::intern(self.vec);
let subst = Substitution::from_iter(&Interner, self.vec);
(self.data, subst)
}
@ -141,7 +141,7 @@ impl TyBuilder<hir_def::AdtId> {
self.vec.push(fallback().cast(&Interner));
} else {
// each default can depend on the previous parameters
let subst_so_far = Substitution::intern(self.vec.clone());
let subst_so_far = Substitution::from_iter(&Interner, self.vec.clone());
self.vec
.push(default_ty.clone().substitute(&Interner, &subst_so_far).cast(&Interner));
}
@ -196,13 +196,13 @@ impl TyBuilder<TypeAliasId> {
}
}
impl<T: TypeWalk + HasInterner<Interner = Interner>> TyBuilder<Binders<T>> {
impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>> {
fn subst_binders(b: Binders<T>) -> Self {
let param_count = b.binders.len(&Interner);
TyBuilder::new(b, param_count)
}
pub fn build(self) -> T {
pub fn build(self) -> <T as Fold<Interner>>::Result {
let (b, subst) = self.build_internal();
b.substitute(&Interner, &subst)
}

View file

@ -1,11 +1,8 @@
//! Implementations of the Chalk `Cast` trait for our types.
use chalk_ir::{
cast::{Cast, CastTo},
interner::HasInterner,
};
use chalk_ir::interner::HasInterner;
use crate::{AliasEq, DomainGoal, GenericArg, GenericArgData, Interner, TraitRef, Ty, WhereClause};
use crate::{CallableSig, ReturnTypeImplTraits};
macro_rules! has_interner {
($t:ty) => {
@ -15,59 +12,5 @@ macro_rules! has_interner {
};
}
has_interner!(WhereClause);
has_interner!(DomainGoal);
has_interner!(GenericArg);
has_interner!(Ty);
impl CastTo<WhereClause> for TraitRef {
fn cast_to(self, _interner: &Interner) -> WhereClause {
WhereClause::Implemented(self)
}
}
impl CastTo<WhereClause> for AliasEq {
fn cast_to(self, _interner: &Interner) -> WhereClause {
WhereClause::AliasEq(self)
}
}
impl CastTo<DomainGoal> for WhereClause {
fn cast_to(self, _interner: &Interner) -> DomainGoal {
DomainGoal::Holds(self)
}
}
impl CastTo<GenericArg> for Ty {
fn cast_to(self, interner: &Interner) -> GenericArg {
GenericArg::new(interner, GenericArgData::Ty(self))
}
}
macro_rules! transitive_impl {
($a:ty, $b:ty, $c:ty) => {
impl CastTo<$c> for $a {
fn cast_to(self, interner: &Interner) -> $c {
self.cast::<$b>(interner).cast(interner)
}
}
};
}
// In Chalk, these can be done as blanket impls, but that doesn't work here
// because of coherence
transitive_impl!(TraitRef, WhereClause, DomainGoal);
transitive_impl!(AliasEq, WhereClause, DomainGoal);
macro_rules! reflexive_impl {
($a:ty) => {
impl CastTo<$a> for $a {
fn cast_to(self, _interner: &Interner) -> $a {
self
}
}
};
}
reflexive_impl!(GenericArg);
has_interner!(CallableSig);
has_interner!(ReturnTypeImplTraits);

View file

@ -287,6 +287,8 @@ impl HirDisplay for GenericArg {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
match self.interned() {
crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
crate::GenericArgData::Const(c) => c.hir_fmt(f),
}
}
}
@ -664,6 +666,8 @@ impl HirDisplay for Ty {
write!(f, "{{unknown}}")?;
}
TyKind::InferenceVar(..) => write!(f, "_")?,
TyKind::Generator(..) => write!(f, "{{generator}}")?,
TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
}
Ok(())
}
@ -741,7 +745,7 @@ fn write_bounds_like_dyn_trait(
if !first {
write!(f, " + ")?;
}
// We assume that the self type is $0 (i.e. the
// We assume that the self type is ^0.0 (i.e. the
// existential) here, which is the only thing that's
// possible in actual Rust, and hence don't print it
write!(f, "{}", f.db.trait_data(trait_).name)?;
@ -783,6 +787,10 @@ fn write_bounds_like_dyn_trait(
}
ty.hir_fmt(f)?;
}
// FIXME implement these
WhereClause::LifetimeOutlives(_) => {}
WhereClause::TypeOutlives(_) => {}
}
first = false;
}
@ -837,6 +845,10 @@ impl HirDisplay for WhereClause {
ty.hir_fmt(f)?;
}
WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
// FIXME implement these
WhereClause::TypeOutlives(..) => {}
WhereClause::LifetimeOutlives(..) => {}
}
Ok(())
}
@ -881,9 +893,11 @@ impl HirDisplay for DomainGoal {
DomainGoal::Holds(wc) => {
write!(f, "Holds(")?;
wc.hir_fmt(f)?;
write!(f, ")")
write!(f, ")")?;
}
_ => write!(f, "?")?,
}
Ok(())
}
}

View file

@ -18,7 +18,7 @@ use std::mem;
use std::ops::Index;
use std::sync::Arc;
use chalk_ir::{cast::Cast, Mutability};
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability};
use hir_def::{
body::Body,
data::{ConstData, FunctionData, StaticData},
@ -38,11 +38,11 @@ use syntax::SmolStr;
use super::{
DomainGoal, Guidance, InEnvironment, ProjectionTy, Solution, TraitEnvironment, TraitRef, Ty,
TypeWalk,
};
use crate::{
db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner, TyBuilder, TyExt, TyKind,
db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic,
lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner,
TyBuilder, TyExt, TyKind,
};
// This lint has a false positive here. See the link below for details.
@ -323,7 +323,7 @@ impl<'a> InferenceContext<'a> {
}
fn insert_type_vars(&mut self, ty: Ty) -> Ty {
ty.fold(&mut |ty| self.insert_type_vars_shallow(ty))
fold_tys(ty, |ty, _| self.insert_type_vars_shallow(ty), DebruijnIndex::INNERMOST)
}
fn resolve_obligations_as_possible(&mut self) {
@ -434,12 +434,16 @@ impl<'a> InferenceContext<'a> {
/// to do it as well.
fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
let ty = self.resolve_ty_as_possible(ty);
ty.fold(&mut |ty| match ty.kind(&Interner) {
TyKind::Alias(AliasTy::Projection(proj_ty)) => {
self.normalize_projection_ty(proj_ty.clone())
}
_ => ty,
})
fold_tys(
ty,
|ty, _| match ty.kind(&Interner) {
TyKind::Alias(AliasTy::Projection(proj_ty)) => {
self.normalize_projection_ty(proj_ty.clone())
}
_ => ty,
},
DebruijnIndex::INNERMOST,
)
}
fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {

View file

@ -71,12 +71,14 @@ impl<'a> InferenceContext<'a> {
}
// Pointer weakening and function to pointer
match (from_ty.interned_mut(), to_ty.kind(&Interner)) {
match (from_ty.kind(&Interner), to_ty.kind(&Interner)) {
// `*mut T` -> `*const T`
(TyKind::Raw(_, inner), TyKind::Raw(m2 @ Mutability::Not, ..)) => {
from_ty = TyKind::Raw(*m2, inner.clone()).intern(&Interner);
}
// `&mut T` -> `&T`
(TyKind::Raw(m1, ..), TyKind::Raw(m2 @ Mutability::Not, ..))
| (TyKind::Ref(m1, ..), TyKind::Ref(m2 @ Mutability::Not, ..)) => {
*m1 = *m2;
(TyKind::Ref(_, lt, inner), TyKind::Ref(m2 @ Mutability::Not, ..)) => {
from_ty = TyKind::Ref(*m2, lt.clone(), inner.clone()).intern(&Interner);
}
// `&T` -> `*const T`
// `&mut T` -> `*mut T`/`*const T`

View file

@ -3,7 +3,7 @@
use std::iter::{repeat, repeat_with};
use std::{mem, sync::Arc};
use chalk_ir::{cast::Cast, Mutability, TyVariableKind};
use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
use hir_def::{
expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
path::{GenericArg, GenericArgs},
@ -24,7 +24,6 @@ use crate::{
utils::{generics, Generics},
AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
TypeWalk,
};
use super::{

View file

@ -2,14 +2,17 @@
use std::borrow::Cow;
use chalk_ir::{FloatTy, IntTy, TyVariableKind, UniverseIndex, VariableKind};
use chalk_ir::{
cast::Cast, fold::Fold, interner::HasInterner, FloatTy, IntTy, TyVariableKind, UniverseIndex,
VariableKind,
};
use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
use super::{DomainGoal, InferenceContext};
use crate::{
AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSubst,
InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyExt, TyKind, TypeWalk,
WhereClause,
fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
DebruijnIndex, FnPointer, FnSubst, InEnvironment, InferenceVar, Interner, Scalar, Substitution,
Ty, TyExt, TyKind, WhereClause,
};
impl<'a> InferenceContext<'a> {
@ -34,7 +37,10 @@ where
}
#[derive(Debug)]
pub(super) struct Canonicalized<T> {
pub(super) struct Canonicalized<T>
where
T: HasInterner<Interner = Interner>,
{
pub(super) value: Canonical<T>,
free_vars: Vec<(InferenceVar, TyVariableKind)>,
}
@ -48,9 +54,14 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
})
}
fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: DebruijnIndex) -> T {
t.fold_binders(
&mut |ty, binders| match ty.kind(&Interner) {
fn do_canonicalize<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
&mut self,
t: T,
binders: DebruijnIndex,
) -> T {
fold_tys(
t,
|ty, binders| match ty.kind(&Interner) {
&TyKind::InferenceVar(var, kind) => {
let inner = from_inference_var(var);
if self.var_stack.contains(&inner) {
@ -76,7 +87,10 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
)
}
fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
fn into_canonicalized<T: HasInterner<Interner = Interner>>(
self,
result: T,
) -> Canonicalized<T> {
let kinds = self
.free_vars
.iter()
@ -103,28 +117,18 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
DomainGoal::Holds(wc) => {
DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST))
}
_ => unimplemented!(),
};
self.into_canonicalized(InEnvironment { goal: result, environment: obligation.environment })
}
}
impl<T> Canonicalized<T> {
impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
pub(super) fn decanonicalize_ty(&self, ty: Ty) -> Ty {
ty.fold_binders(
&mut |ty, binders| {
if let TyKind::BoundVar(bound) = ty.kind(&Interner) {
if bound.debruijn >= binders {
let (v, k) = self.free_vars[bound.index];
TyKind::InferenceVar(v, k).intern(&Interner)
} else {
ty
}
} else {
ty
}
},
DebruijnIndex::INNERMOST,
)
crate::fold_free_vars(ty, |bound, _binders| {
let (v, k) = self.free_vars[bound.index];
TyKind::InferenceVar(v, k).intern(&Interner)
})
}
pub(super) fn apply_solution(
@ -136,15 +140,17 @@ impl<T> Canonicalized<T> {
let new_vars = Substitution::from_iter(
&Interner,
solution.binders.iter(&Interner).map(|k| match k.kind {
VariableKind::Ty(TyVariableKind::General) => ctx.table.new_type_var(),
VariableKind::Ty(TyVariableKind::Integer) => ctx.table.new_integer_var(),
VariableKind::Ty(TyVariableKind::Float) => ctx.table.new_float_var(),
// HACK: Chalk can sometimes return new lifetime variables. We
// want to just skip them, but to not mess up the indices of
// other variables, we'll just create a new type variable in
// their place instead. This should not matter (we never see the
// actual *uses* of the lifetime variable).
VariableKind::Lifetime => ctx.table.new_type_var(),
VariableKind::Ty(TyVariableKind::General) => {
ctx.table.new_type_var().cast(&Interner)
}
VariableKind::Ty(TyVariableKind::Integer) => {
ctx.table.new_integer_var().cast(&Interner)
}
VariableKind::Ty(TyVariableKind::Float) => {
ctx.table.new_float_var().cast(&Interner)
}
// Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
VariableKind::Lifetime => static_lifetime().cast(&Interner),
_ => panic!("const variable in solution"),
}),
);
@ -488,55 +494,63 @@ impl InferenceTable {
/// be resolved as far as possible, i.e. contain no type variables with
/// known type.
fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
ty.fold(&mut |ty| match ty.kind(&Interner) {
&TyKind::InferenceVar(tv, kind) => {
let inner = from_inference_var(tv);
if tv_stack.contains(&inner) {
cov_mark::hit!(type_var_cycles_resolve_as_possible);
// recursive type
return self.type_variable_table.fallback_value(tv, kind);
fold_tys(
ty,
|ty, _| match ty.kind(&Interner) {
&TyKind::InferenceVar(tv, kind) => {
let inner = from_inference_var(tv);
if tv_stack.contains(&inner) {
cov_mark::hit!(type_var_cycles_resolve_as_possible);
// recursive type
return self.type_variable_table.fallback_value(tv, kind);
}
if let Some(known_ty) =
self.var_unification_table.inlined_probe_value(inner).known()
{
// known_ty may contain other variables that are known by now
tv_stack.push(inner);
let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone());
tv_stack.pop();
result
} else {
ty
}
}
if let Some(known_ty) =
self.var_unification_table.inlined_probe_value(inner).known()
{
// known_ty may contain other variables that are known by now
tv_stack.push(inner);
let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone());
tv_stack.pop();
result
} else {
ty
}
}
_ => ty,
})
_ => ty,
},
DebruijnIndex::INNERMOST,
)
}
/// Resolves the type completely; type variables without known type are
/// replaced by TyKind::Unknown.
fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
ty.fold(&mut |ty| match ty.kind(&Interner) {
&TyKind::InferenceVar(tv, kind) => {
let inner = from_inference_var(tv);
if tv_stack.contains(&inner) {
cov_mark::hit!(type_var_cycles_resolve_completely);
// recursive type
return self.type_variable_table.fallback_value(tv, kind);
fold_tys(
ty,
|ty, _| match ty.kind(&Interner) {
&TyKind::InferenceVar(tv, kind) => {
let inner = from_inference_var(tv);
if tv_stack.contains(&inner) {
cov_mark::hit!(type_var_cycles_resolve_completely);
// recursive type
return self.type_variable_table.fallback_value(tv, kind);
}
if let Some(known_ty) =
self.var_unification_table.inlined_probe_value(inner).known()
{
// known_ty may contain other variables that are known by now
tv_stack.push(inner);
let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone());
tv_stack.pop();
result
} else {
self.type_variable_table.fallback_value(tv, kind)
}
}
if let Some(known_ty) =
self.var_unification_table.inlined_probe_value(inner).known()
{
// known_ty may contain other variables that are known by now
tv_stack.push(inner);
let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone());
tv_stack.pop();
result
} else {
self.type_variable_table.fallback_value(tv, kind)
}
}
_ => ty,
})
_ => ty,
},
DebruijnIndex::INNERMOST,
)
}
}

View file

@ -1,5 +1,6 @@
//! The type system. We currently use this to infer types for completion, hover
//! information and various assists.
#[allow(unused)]
macro_rules! eprintln {
($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
@ -17,7 +18,6 @@ mod chalk_cast;
mod chalk_ext;
mod builder;
mod walk;
mod types;
pub mod display;
pub mod db;
@ -31,7 +31,11 @@ mod test_db;
use std::sync::Arc;
use base_db::salsa;
use chalk_ir::UintTy;
use chalk_ir::{
fold::{Fold, Shift},
interner::HasInterner,
UintTy,
};
use hir_def::{
expr::ExprId, type_ref::Rawness, ConstParamId, LifetimeParamId, TraitId, TypeAliasId,
TypeParamId,
@ -48,7 +52,6 @@ pub use lower::{
TyDefId, TyLoweringContext, ValueTyDefId,
};
pub use traits::{chalk::Interner, TraitEnvironment};
pub use types::*;
pub use walk::TypeWalk;
pub use chalk_ir::{
@ -65,6 +68,21 @@ pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
pub type VariableKind = chalk_ir::VariableKind<Interner>;
pub type VariableKinds = chalk_ir::VariableKinds<Interner>;
pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
pub type Binders<T> = chalk_ir::Binders<T>;
pub type Substitution = chalk_ir::Substitution<Interner>;
pub type GenericArg = chalk_ir::GenericArg<Interner>;
pub type GenericArgData = chalk_ir::GenericArgData<Interner>;
pub type Ty = chalk_ir::Ty<Interner>;
pub type TyKind = chalk_ir::TyKind<Interner>;
pub type DynTy = chalk_ir::DynTy<Interner>;
pub type FnPointer = chalk_ir::FnPointer<Interner>;
// pub type FnSubst = chalk_ir::FnSubst<Interner>;
pub use chalk_ir::FnSubst;
pub type ProjectionTy = chalk_ir::ProjectionTy<Interner>;
pub type AliasTy = chalk_ir::AliasTy<Interner>;
pub type OpaqueTy = chalk_ir::OpaqueTy<Interner>;
pub type InferenceVar = chalk_ir::InferenceVar;
pub type Lifetime = chalk_ir::Lifetime<Interner>;
pub type LifetimeData = chalk_ir::LifetimeData<Interner>;
@ -79,9 +97,20 @@ pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
pub type FnSig = chalk_ir::FnSig<Interner>;
pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
pub type DomainGoal = chalk_ir::DomainGoal<Interner>;
pub type AliasEq = chalk_ir::AliasEq<Interner>;
pub type Solution = chalk_solve::Solution<Interner>;
pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
pub type Guidance = chalk_solve::Guidance<Interner>;
pub type WhereClause = chalk_ir::WhereClause<Interner>;
// FIXME: get rid of this
pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
Substitution::intern(s.interned()[..std::cmp::min(s.len(&Interner), n)].into())
Substitution::from_iter(
&Interner,
s.interned()[..std::cmp::min(s.len(&Interner), n)].iter().cloned(),
)
}
/// Return an index of a parameter in the generic type parameter list by it's id.
@ -91,12 +120,15 @@ pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
pub fn wrap_empty_binders<T>(value: T) -> Binders<T>
where
T: TypeWalk,
T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>,
{
Binders::empty(&Interner, value.shifted_in_from(DebruijnIndex::ONE))
Binders::empty(&Interner, value.shifted_in_from(&Interner, DebruijnIndex::ONE))
}
pub fn make_only_type_binders<T>(num_vars: usize, value: T) -> Binders<T> {
pub fn make_only_type_binders<T: HasInterner<Interner = Interner>>(
num_vars: usize,
value: T,
) -> Binders<T> {
Binders::new(
VariableKinds::from_iter(
&Interner,
@ -108,7 +140,7 @@ pub fn make_only_type_binders<T>(num_vars: usize, value: T) -> Binders<T> {
}
// FIXME: get rid of this
pub fn make_canonical<T>(
pub fn make_canonical<T: HasInterner<Interner = Interner>>(
value: T,
kinds: impl IntoIterator<Item = TyVariableKind>,
) -> Canonical<T> {
@ -121,6 +153,14 @@ pub fn make_canonical<T>(
Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
}
pub type TraitRef = chalk_ir::TraitRef<Interner>;
pub type QuantifiedWhereClause = Binders<WhereClause>;
pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>;
pub type Canonical<T> = chalk_ir::Canonical<T>;
/// A function signature as seen by type inference: Several parameter types and
/// one return type.
#[derive(Clone, PartialEq, Eq, Debug)]
@ -144,7 +184,7 @@ impl CallableSig {
params_and_return: fn_ptr
.substitution
.clone()
.shifted_out_to(DebruijnIndex::ONE)
.shifted_out_to(&Interner, DebruijnIndex::ONE)
.expect("unexpected lifetime vars in fn ptr")
.0
.interned()
@ -164,7 +204,22 @@ impl CallableSig {
}
}
impl Ty {}
impl Fold<Interner> for CallableSig {
type Result = CallableSig;
fn fold_with<'i>(
self,
folder: &mut dyn chalk_ir::fold::Folder<'i, Interner>,
outer_binder: DebruijnIndex,
) -> chalk_ir::Fallible<Self::Result>
where
Interner: 'i,
{
let vec = self.params_and_return.to_vec();
let folded = vec.fold_with(folder, outer_binder)?;
Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum ImplTraitId {
@ -244,3 +299,56 @@ pub fn dummy_usize_const() -> Const {
}
.intern(&Interner)
}
pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>(
t: T,
f: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
) -> T::Result {
use chalk_ir::{fold::Folder, Fallible};
struct FreeVarFolder<F>(F);
impl<'i, F: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i> Folder<'i, Interner> for FreeVarFolder<F> {
fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> {
self
}
fn interner(&self) -> &'i Interner {
&Interner
}
fn fold_free_var_ty(
&mut self,
bound_var: BoundVar,
outer_binder: DebruijnIndex,
) -> Fallible<Ty> {
Ok(self.0(bound_var, outer_binder))
}
}
t.fold_with(&mut FreeVarFolder(f), DebruijnIndex::INNERMOST).expect("fold failed unexpectedly")
}
pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
t: T,
f: impl FnMut(Ty, DebruijnIndex) -> Ty,
binders: DebruijnIndex,
) -> T::Result {
use chalk_ir::{
fold::{Folder, SuperFold},
Fallible,
};
struct TyFolder<F>(F);
impl<'i, F: FnMut(Ty, DebruijnIndex) -> Ty + 'i> Folder<'i, Interner> for TyFolder<F> {
fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> {
self
}
fn interner(&self) -> &'i Interner {
&Interner
}
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
Ok(self.0(ty, outer_binder))
}
}
t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
}

View file

@ -8,7 +8,7 @@
use std::{iter, sync::Arc};
use base_db::CrateId;
use chalk_ir::{cast::Cast, Mutability, Safety};
use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
use hir_def::{
adt::StructKind,
builtin_type::BuiltinType,
@ -35,7 +35,7 @@ use crate::{
AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
FnSubst, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, TypeWalk, WhereClause,
TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
};
#[derive(Debug)]
@ -488,7 +488,7 @@ impl<'a> TyLoweringContext<'a> {
};
// We need to shift in the bound vars, since
// associated_type_shorthand_candidates does not do that
let substs = substs.shifted_in_from(self.in_binders);
let substs = substs.shifted_in_from(&Interner, self.in_binders);
// FIXME handle type parameters on the segment
return Some(
TyKind::Alias(AliasTy::Projection(ProjectionTy {
@ -847,7 +847,7 @@ pub fn associated_type_shorthand_candidates<R>(
// FIXME: how to correctly handle higher-ranked bounds here?
WhereClause::Implemented(tr) => search(
tr.clone()
.shifted_out_to(DebruijnIndex::ONE)
.shifted_out_to(&Interner, DebruijnIndex::ONE)
.expect("FIXME unexpected higher-ranked trait bound"),
),
_ => None,
@ -950,8 +950,7 @@ pub(crate) fn trait_environment_query(
traits_in_scope
.push((tr.self_type_parameter(&Interner).clone(), tr.hir_trait_id()));
}
let program_clause: chalk_ir::ProgramClause<Interner> =
pred.clone().to_chalk(db).cast(&Interner);
let program_clause: chalk_ir::ProgramClause<Interner> = pred.clone().cast(&Interner);
clauses.push(program_clause.into_from_env_clause(&Interner));
}
}
@ -974,7 +973,7 @@ pub(crate) fn trait_environment_query(
let substs = TyBuilder::type_params_subst(db, trait_id);
let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
let pred = WhereClause::Implemented(trait_ref);
let program_clause: chalk_ir::ProgramClause<Interner> = pred.to_chalk(db).cast(&Interner);
let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
clauses.push(program_clause.into_from_env_clause(&Interner));
}
@ -1016,22 +1015,16 @@ pub(crate) fn generic_defaults_query(
p.default.as_ref().map_or(TyKind::Error.intern(&Interner), |t| ctx.lower_ty(t));
// Each default can only refer to previous parameters.
ty = ty.fold_binders(
&mut |ty, binders| match ty.kind(&Interner) {
TyKind::BoundVar(BoundVar { debruijn, index }) if *debruijn == binders => {
if *index >= idx {
// type variable default referring to parameter coming
// after it. This is forbidden (FIXME: report
// diagnostic)
TyKind::Error.intern(&Interner)
} else {
ty
}
}
_ => ty,
},
DebruijnIndex::INNERMOST,
);
ty = crate::fold_free_vars(ty, |bound, binders| {
if bound.index >= idx && bound.debruijn == DebruijnIndex::INNERMOST {
// type variable default referring to parameter coming
// after it. This is forbidden (FIXME: report
// diagnostic)
TyKind::Error.intern(&Interner)
} else {
bound.shifted_in_from(binders).to_ty(&Interner)
}
});
crate::make_only_type_binders(idx, ty)
})
@ -1307,6 +1300,6 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
}
}
fn make_binders<T>(generics: &Generics, value: T) -> Binders<T> {
fn make_binders<T: HasInterner<Interner = Interner>>(generics: &Generics, value: T) -> Binders<T> {
crate::make_only_type_binders(generics.len(), value)
}

View file

@ -23,7 +23,7 @@ use crate::{
utils::all_super_traits,
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId,
InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder,
TyExt, TyKind, TypeWalk,
TyExt, TyKind,
};
/// This is used as a key for indexing impls.
@ -757,20 +757,13 @@ pub(crate) fn inherent_impl_substs(
/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
/// num_vars_to_keep) by `TyKind::Unknown`.
fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution {
s.fold_binders(
&mut |ty, binders| {
if let TyKind::BoundVar(bound) = ty.kind(&Interner) {
if bound.index >= num_vars_to_keep && bound.debruijn >= binders {
TyKind::Error.intern(&Interner)
} else {
ty
}
} else {
ty
}
},
DebruijnIndex::INNERMOST,
)
crate::fold_free_vars(s, |bound, binders| {
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
TyKind::Error.intern(&Interner)
} else {
bound.shifted_in_from(binders).to_ty(&Interner)
}
})
}
fn transform_receiver_ty(

View file

@ -12,7 +12,7 @@ use crate::{
Solution, TraitRefExt, Ty, TyKind, WhereClause,
};
use self::chalk::{from_chalk, Interner, ToChalk};
use self::chalk::Interner;
pub(crate) mod chalk;
@ -81,6 +81,7 @@ pub(crate) fn trait_solve_query(
db.trait_data(it.hir_trait_id()).name.to_string()
}
DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(),
_ => "??".to_string(),
});
log::info!("trait_solve_query({})", goal.value.goal.display(db));
@ -95,13 +96,12 @@ pub(crate) fn trait_solve_query(
}
}
let canonical = goal.to_chalk(db).cast(&Interner);
let canonical = goal.cast(&Interner);
// We currently don't deal with universes (I think / hope they're not yet
// relevant for our use cases?)
let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
let solution = solve(db, krate, &u_canonical);
solution.map(|solution| solution_from_chalk(db, solution))
solve(db, krate, &u_canonical)
}
fn solve(
@ -169,26 +169,6 @@ fn is_chalk_print() -> bool {
std::env::var("CHALK_PRINT").is_ok()
}
fn solution_from_chalk(
db: &dyn HirDatabase,
solution: chalk_solve::Solution<Interner>,
) -> Solution {
match solution {
chalk_solve::Solution::Unique(constr_subst) => {
Solution::Unique(from_chalk(db, constr_subst))
}
chalk_solve::Solution::Ambig(chalk_solve::Guidance::Definite(subst)) => {
Solution::Ambig(Guidance::Definite(from_chalk(db, subst)))
}
chalk_solve::Solution::Ambig(chalk_solve::Guidance::Suggested(subst)) => {
Solution::Ambig(Guidance::Suggested(from_chalk(db, subst)))
}
chalk_solve::Solution::Ambig(chalk_solve::Guidance::Unknown) => {
Solution::Ambig(Guidance::Unknown)
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FnTrait {
FnOnce,

View file

@ -17,16 +17,14 @@ use super::ChalkContext;
use crate::{
db::HirDatabase,
display::HirDisplay,
from_assoc_type_id,
from_assoc_type_id, make_only_type_binders,
method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
to_assoc_type_id, to_chalk_trait_id,
utils::generics,
AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution,
TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
};
use mapping::{
convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
};
use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, TypeAliasAsValue};
pub use self::interner::Interner;
pub(crate) use self::interner::*;
@ -86,7 +84,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
debug!("impls_for_trait {:?}", trait_id);
let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
let ty: Ty = parameters[0].assert_ty_ref(&Interner).clone();
fn binder_kind(
ty: &Ty,
@ -187,16 +185,11 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
let data = &datas.impl_traits[idx as usize];
let bound = OpaqueTyDatumBound {
bounds: make_binders(
data.bounds
.skip_binders()
.iter()
.cloned()
.map(|b| b.to_chalk(self.db))
.collect(),
bounds: make_only_type_binders(
1,
data.bounds.skip_binders().iter().cloned().collect(),
),
where_clauses: make_binders(vec![], 0),
where_clauses: make_only_type_binders(0, vec![]),
};
chalk_ir::Binders::new(binders, bound)
}
@ -244,25 +237,25 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
.intern(&Interner),
});
let bound = OpaqueTyDatumBound {
bounds: make_binders(
vec![
crate::wrap_empty_binders(impl_bound).to_chalk(self.db),
crate::wrap_empty_binders(proj_bound).to_chalk(self.db),
],
bounds: make_only_type_binders(
1,
vec![
crate::wrap_empty_binders(impl_bound),
crate::wrap_empty_binders(proj_bound),
],
),
where_clauses: make_binders(vec![], 0),
where_clauses: make_only_type_binders(0, vec![]),
};
// The opaque type has 1 parameter.
make_binders(bound, 1)
make_only_type_binders(1, bound)
} else {
// If failed to find Symbols value as variable is void: Future::Output, return empty bounds as fallback.
let bound = OpaqueTyDatumBound {
bounds: make_binders(vec![], 0),
where_clauses: make_binders(vec![], 0),
bounds: make_only_type_binders(0, vec![]),
where_clauses: make_only_type_binders(0, vec![]),
};
// The opaque type has 1 parameter.
make_binders(bound, 1)
make_only_type_binders(1, bound)
}
}
};
@ -272,7 +265,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
// FIXME: actually provide the hidden type; it is relevant for auto traits
TyKind::Error.intern(&Interner).to_chalk(self.db)
TyKind::Error.intern(&Interner)
}
fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool {
@ -293,29 +286,28 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
_closure_id: chalk_ir::ClosureId<Interner>,
substs: &chalk_ir::Substitution<Interner>,
) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> {
let sig_ty: Ty =
from_chalk(self.db, substs.at(&Interner, 0).assert_ty_ref(&Interner).clone());
let sig_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner).clone();
let sig = &sig_ty.callable_sig(self.db).expect("first closure param should be fn ptr");
let io = rust_ir::FnDefInputsAndOutputDatum {
argument_types: sig.params().iter().map(|ty| ty.clone().to_chalk(self.db)).collect(),
return_type: sig.ret().clone().to_chalk(self.db),
argument_types: sig.params().iter().cloned().collect(),
return_type: sig.ret().clone(),
};
make_binders(io.shifted_in(&Interner), 0)
make_only_type_binders(0, io.shifted_in(&Interner))
}
fn closure_upvars(
&self,
_closure_id: chalk_ir::ClosureId<Interner>,
_substs: &chalk_ir::Substitution<Interner>,
) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> {
let ty = TyBuilder::unit().to_chalk(self.db);
make_binders(ty, 0)
let ty = TyBuilder::unit();
make_only_type_binders(0, ty)
}
fn closure_fn_substitution(
&self,
_closure_id: chalk_ir::ClosureId<Interner>,
_substs: &chalk_ir::Substitution<Interner>,
) -> chalk_ir::Substitution<Interner> {
Substitution::empty(&Interner).to_chalk(self.db)
Substitution::empty(&Interner)
}
fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String {
@ -410,10 +402,10 @@ pub(crate) fn associated_ty_data_query(
let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses };
let datum = AssociatedTyDatum {
trait_id: trait_.to_chalk(db),
trait_id: to_chalk_trait_id(trait_),
id,
name: type_alias,
binders: make_binders(bound_data, generic_params.len()),
binders: make_only_type_binders(generic_params.len(), bound_data),
};
Arc::new(datum)
}
@ -446,7 +438,7 @@ pub(crate) fn trait_datum_query(
lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
let trait_datum = TraitDatum {
id: trait_id,
binders: make_binders(trait_datum_bound, bound_vars.len(&Interner)),
binders: make_only_type_binders(bound_vars.len(&Interner), trait_datum_bound),
flags,
associated_ty_ids,
well_known,
@ -515,7 +507,7 @@ pub(crate) fn struct_datum_query(
// FIXME set ADT kind
kind: rust_ir::AdtKind::Struct,
id: struct_id,
binders: make_binders(struct_datum_bound, num_params),
binders: make_only_type_binders(num_params, struct_datum_bound),
flags,
};
Arc::new(struct_datum)
@ -563,7 +555,6 @@ fn impl_def_datum(
trait_ref.display(db),
where_clauses
);
let trait_ref = trait_ref.to_chalk(db);
let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive };
@ -585,7 +576,7 @@ fn impl_def_datum(
.collect();
debug!("impl_datum: {:?}", impl_datum_bound);
let impl_datum = ImplDatum {
binders: make_binders(impl_datum_bound, bound_vars.len(&Interner)),
binders: make_only_type_binders(bound_vars.len(&Interner), impl_datum_bound),
impl_type,
polarity,
associated_ty_value_ids,
@ -624,7 +615,7 @@ fn type_alias_associated_ty_value(
.associated_type_by_name(&type_alias_data.name)
.expect("assoc ty value should not exist"); // validated when building the impl data as well
let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders();
let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) };
let value_bound = rust_ir::AssociatedTyValueBound { ty };
let value = rust_ir::AssociatedTyValue {
impl_id: impl_id.to_chalk(db),
associated_ty_id: to_assoc_type_id(assoc_ty),
@ -645,13 +636,13 @@ pub(crate) fn fn_def_datum_query(
let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
let bound = rust_ir::FnDefDatumBound {
// Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
inputs_and_output: make_binders(
inputs_and_output: make_only_type_binders(
0,
rust_ir::FnDefInputsAndOutputDatum {
argument_types: sig.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(),
return_type: sig.ret().clone().to_chalk(db),
argument_types: sig.params().iter().cloned().collect(),
return_type: sig.ret().clone(),
}
.shifted_in(&Interner),
0,
),
where_clauses,
};

View file

@ -3,233 +3,20 @@
//! Chalk (in both directions); plus some helper functions for more specialized
//! conversions.
use chalk_ir::{cast::Cast, interner::HasInterner};
use chalk_ir::cast::Cast;
use chalk_solve::rust_ir;
use base_db::salsa::InternKey;
use hir_def::{GenericDefId, TypeAliasId};
use crate::{
db::HirDatabase, static_lifetime, AliasTy, CallableDefId, Canonical, ConstrainedSubst,
DomainGoal, FnPointer, GenericArg, InEnvironment, OpaqueTy, ProjectionTy, ProjectionTyExt,
QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
db::HirDatabase, AliasTy, CallableDefId, ProjectionTyExt, QuantifiedWhereClause, Substitution,
Ty, WhereClause,
};
use super::interner::*;
use super::*;
impl ToChalk for Ty {
type Chalk = chalk_ir::Ty<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
match self.into_inner() {
TyKind::Ref(m, lt, ty) => {
chalk_ir::TyKind::Ref(m, lt, ty.to_chalk(db)).intern(&Interner)
}
TyKind::Array(ty, size) => {
chalk_ir::TyKind::Array(ty.to_chalk(db), size).intern(&Interner)
}
TyKind::Function(FnPointer { sig, substitution: substs, num_binders }) => {
let substitution = chalk_ir::FnSubst(substs.0.to_chalk(db));
chalk_ir::TyKind::Function(chalk_ir::FnPointer { num_binders, sig, substitution })
.intern(&Interner)
}
TyKind::AssociatedType(assoc_type_id, substs) => {
let substitution = substs.to_chalk(db);
chalk_ir::TyKind::AssociatedType(assoc_type_id, substitution).intern(&Interner)
}
TyKind::OpaqueType(id, substs) => {
let substitution = substs.to_chalk(db);
chalk_ir::TyKind::OpaqueType(id, substitution).intern(&Interner)
}
TyKind::Foreign(id) => chalk_ir::TyKind::Foreign(id).intern(&Interner),
TyKind::Scalar(scalar) => chalk_ir::TyKind::Scalar(scalar).intern(&Interner),
TyKind::Tuple(cardinality, substs) => {
let substitution = substs.to_chalk(db);
chalk_ir::TyKind::Tuple(cardinality, substitution).intern(&Interner)
}
TyKind::Raw(mutability, ty) => {
let ty = ty.to_chalk(db);
chalk_ir::TyKind::Raw(mutability, ty).intern(&Interner)
}
TyKind::Slice(ty) => chalk_ir::TyKind::Slice(ty.to_chalk(db)).intern(&Interner),
TyKind::Str => chalk_ir::TyKind::Str.intern(&Interner),
TyKind::FnDef(id, substs) => {
let substitution = substs.to_chalk(db);
chalk_ir::TyKind::FnDef(id, substitution).intern(&Interner)
}
TyKind::Never => chalk_ir::TyKind::Never.intern(&Interner),
TyKind::Closure(closure_id, substs) => {
let substitution = substs.to_chalk(db);
chalk_ir::TyKind::Closure(closure_id, substitution).intern(&Interner)
}
TyKind::Adt(adt_id, substs) => {
let substitution = substs.to_chalk(db);
chalk_ir::TyKind::Adt(adt_id, substitution).intern(&Interner)
}
TyKind::Alias(AliasTy::Projection(proj_ty)) => {
chalk_ir::AliasTy::Projection(proj_ty.to_chalk(db))
.cast(&Interner)
.intern(&Interner)
}
TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)).cast(&Interner).intern(&Interner)
}
TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner),
TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner),
TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"),
TyKind::Dyn(dyn_ty) => {
let (bounds, binders) = dyn_ty.bounds.into_value_and_skipped_binders();
let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter(
&Interner,
bounds.interned().iter().cloned().map(|p| p.to_chalk(db)),
);
let bounded_ty = chalk_ir::DynTy {
bounds: chalk_ir::Binders::new(binders, where_clauses),
lifetime: dyn_ty.lifetime,
};
chalk_ir::TyKind::Dyn(bounded_ty).intern(&Interner)
}
TyKind::Error => chalk_ir::TyKind::Error.intern(&Interner),
}
}
fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self {
match chalk.data(&Interner).kind.clone() {
chalk_ir::TyKind::Error => TyKind::Error,
chalk_ir::TyKind::Array(ty, size) => TyKind::Array(from_chalk(db, ty), size),
chalk_ir::TyKind::Placeholder(idx) => TyKind::Placeholder(idx),
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(proj)) => {
TyKind::Alias(AliasTy::Projection(from_chalk(db, proj)))
}
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => {
TyKind::Alias(AliasTy::Opaque(from_chalk(db, opaque_ty)))
}
chalk_ir::TyKind::Function(chalk_ir::FnPointer {
num_binders,
sig,
substitution,
..
}) => {
assert_eq!(num_binders, 0);
let substs = crate::FnSubst(from_chalk(db, substitution.0));
TyKind::Function(FnPointer { num_binders, sig, substitution: substs })
}
chalk_ir::TyKind::BoundVar(idx) => TyKind::BoundVar(idx),
chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Error,
chalk_ir::TyKind::Dyn(dyn_ty) => {
assert_eq!(dyn_ty.bounds.binders.len(&Interner), 1);
let (bounds, binders) = dyn_ty.bounds.into_value_and_skipped_binders();
let where_clauses = crate::QuantifiedWhereClauses::from_iter(
&Interner,
bounds.interned().iter().cloned().map(|p| from_chalk(db, p)),
);
TyKind::Dyn(crate::DynTy {
bounds: crate::Binders::new(binders, where_clauses),
// HACK: we sometimes get lifetime variables back in solutions
// from Chalk, and don't have the infrastructure to substitute
// them yet. So for now we just turn them into 'static right
// when we get them
lifetime: static_lifetime(),
})
}
chalk_ir::TyKind::Adt(adt_id, subst) => TyKind::Adt(adt_id, from_chalk(db, subst)),
chalk_ir::TyKind::AssociatedType(type_id, subst) => {
TyKind::AssociatedType(type_id, from_chalk(db, subst))
}
chalk_ir::TyKind::OpaqueType(opaque_type_id, subst) => {
TyKind::OpaqueType(opaque_type_id, from_chalk(db, subst))
}
chalk_ir::TyKind::Scalar(scalar) => TyKind::Scalar(scalar),
chalk_ir::TyKind::Tuple(cardinality, subst) => {
TyKind::Tuple(cardinality, from_chalk(db, subst))
}
chalk_ir::TyKind::Raw(mutability, ty) => TyKind::Raw(mutability, from_chalk(db, ty)),
chalk_ir::TyKind::Slice(ty) => TyKind::Slice(from_chalk(db, ty)),
chalk_ir::TyKind::Ref(mutability, _lifetime, ty) => {
// HACK: we sometimes get lifetime variables back in solutions
// from Chalk, and don't have the infrastructure to substitute
// them yet. So for now we just turn them into 'static right
// when we get them
TyKind::Ref(mutability, static_lifetime(), from_chalk(db, ty))
}
chalk_ir::TyKind::Str => TyKind::Str,
chalk_ir::TyKind::Never => TyKind::Never,
chalk_ir::TyKind::FnDef(fn_def_id, subst) => {
TyKind::FnDef(fn_def_id, from_chalk(db, subst))
}
chalk_ir::TyKind::Closure(id, subst) => TyKind::Closure(id, from_chalk(db, subst)),
chalk_ir::TyKind::Foreign(foreign_def_id) => TyKind::Foreign(foreign_def_id),
chalk_ir::TyKind::Generator(_, _) => unimplemented!(), // FIXME
chalk_ir::TyKind::GeneratorWitness(_, _) => unimplemented!(), // FIXME
}
.intern(&Interner)
}
}
impl ToChalk for GenericArg {
type Chalk = chalk_ir::GenericArg<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
match self.interned() {
crate::GenericArgData::Ty(ty) => ty.clone().to_chalk(db).cast(&Interner),
}
}
fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
match chalk.interned() {
chalk_ir::GenericArgData::Ty(ty) => Ty::from_chalk(db, ty.clone()).cast(&Interner),
chalk_ir::GenericArgData::Lifetime(_) => unimplemented!(),
chalk_ir::GenericArgData::Const(_) => unimplemented!(),
}
}
}
impl ToChalk for Substitution {
type Chalk = chalk_ir::Substitution<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> {
chalk_ir::Substitution::from_iter(
&Interner,
self.iter(&Interner).map(|ty| ty.clone().to_chalk(db)),
)
}
fn from_chalk(
db: &dyn HirDatabase,
parameters: chalk_ir::Substitution<Interner>,
) -> Substitution {
let tys = parameters.iter(&Interner).map(|p| from_chalk(db, p.clone())).collect();
Substitution::intern(tys)
}
}
impl ToChalk for TraitRef {
type Chalk = chalk_ir::TraitRef<Interner>;
fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> {
let trait_id = self.trait_id;
let substitution = self.substitution.to_chalk(db);
chalk_ir::TraitRef { trait_id, substitution }
}
fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self {
let trait_id = trait_ref.trait_id;
let substs = from_chalk(db, trait_ref.substitution);
TraitRef { trait_id, substitution: substs }
}
}
impl ToChalk for hir_def::TraitId {
type Chalk = TraitId;
@ -283,208 +70,6 @@ impl ToChalk for TypeAliasAsValue {
}
}
impl ToChalk for WhereClause {
type Chalk = chalk_ir::WhereClause<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::WhereClause<Interner> {
match self {
WhereClause::Implemented(trait_ref) => {
chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db))
}
WhereClause::AliasEq(alias_eq) => chalk_ir::WhereClause::AliasEq(alias_eq.to_chalk(db)),
}
}
fn from_chalk(
db: &dyn HirDatabase,
where_clause: chalk_ir::WhereClause<Interner>,
) -> WhereClause {
match where_clause {
chalk_ir::WhereClause::Implemented(tr) => WhereClause::Implemented(from_chalk(db, tr)),
chalk_ir::WhereClause::AliasEq(alias_eq) => {
WhereClause::AliasEq(from_chalk(db, alias_eq))
}
chalk_ir::WhereClause::LifetimeOutlives(_) => {
// we shouldn't get these from Chalk
panic!("encountered LifetimeOutlives from Chalk")
}
chalk_ir::WhereClause::TypeOutlives(_) => {
// we shouldn't get these from Chalk
panic!("encountered TypeOutlives from Chalk")
}
}
}
}
impl ToChalk for ProjectionTy {
type Chalk = chalk_ir::ProjectionTy<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> {
chalk_ir::ProjectionTy {
associated_ty_id: self.associated_ty_id,
substitution: self.substitution.to_chalk(db),
}
}
fn from_chalk(
db: &dyn HirDatabase,
projection_ty: chalk_ir::ProjectionTy<Interner>,
) -> ProjectionTy {
ProjectionTy {
associated_ty_id: projection_ty.associated_ty_id,
substitution: from_chalk(db, projection_ty.substitution),
}
}
}
impl ToChalk for OpaqueTy {
type Chalk = chalk_ir::OpaqueTy<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
chalk_ir::OpaqueTy {
opaque_ty_id: self.opaque_ty_id,
substitution: self.substitution.to_chalk(db),
}
}
fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
OpaqueTy {
opaque_ty_id: chalk.opaque_ty_id,
substitution: from_chalk(db, chalk.substitution),
}
}
}
impl ToChalk for AliasTy {
type Chalk = chalk_ir::AliasTy<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
match self {
AliasTy::Projection(projection_ty) => {
chalk_ir::AliasTy::Projection(projection_ty.to_chalk(db))
}
AliasTy::Opaque(opaque_ty) => chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)),
}
}
fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
match chalk {
chalk_ir::AliasTy::Projection(projection_ty) => {
AliasTy::Projection(from_chalk(db, projection_ty))
}
chalk_ir::AliasTy::Opaque(opaque_ty) => AliasTy::Opaque(from_chalk(db, opaque_ty)),
}
}
}
impl ToChalk for AliasEq {
type Chalk = chalk_ir::AliasEq<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
chalk_ir::AliasEq { alias: self.alias.to_chalk(db), ty: self.ty.to_chalk(db) }
}
fn from_chalk(db: &dyn HirDatabase, alias_eq: chalk_ir::AliasEq<Interner>) -> Self {
AliasEq { alias: from_chalk(db, alias_eq.alias), ty: from_chalk(db, alias_eq.ty) }
}
}
impl ToChalk for DomainGoal {
type Chalk = chalk_ir::DomainGoal<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> {
match self {
DomainGoal::Holds(WhereClause::Implemented(tr)) => tr.to_chalk(db).cast(&Interner),
DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => {
alias_eq.to_chalk(db).cast(&Interner)
}
}
}
fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self {
unimplemented!()
}
}
impl<T> ToChalk for Canonical<T>
where
T: ToChalk,
T::Chalk: HasInterner<Interner = Interner>,
{
type Chalk = chalk_ir::Canonical<T::Chalk>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
let value = self.value.to_chalk(db);
chalk_ir::Canonical { value, binders: self.binders }
}
fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
Canonical { binders: canonical.binders, value: from_chalk(db, canonical.value) }
}
}
impl<T: ToChalk> ToChalk for InEnvironment<T>
where
T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
{
type Chalk = chalk_ir::InEnvironment<T::Chalk>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
chalk_ir::InEnvironment { environment: self.environment, goal: self.goal.to_chalk(db) }
}
fn from_chalk(
_db: &dyn HirDatabase,
_in_env: chalk_ir::InEnvironment<T::Chalk>,
) -> InEnvironment<T> {
unimplemented!()
}
}
impl<T: ToChalk> ToChalk for crate::Binders<T>
where
T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
{
type Chalk = chalk_ir::Binders<T::Chalk>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Binders<T::Chalk> {
let (value, binders) = self.into_value_and_skipped_binders();
chalk_ir::Binders::new(binders, value.to_chalk(db))
}
fn from_chalk(db: &dyn HirDatabase, binders: chalk_ir::Binders<T::Chalk>) -> crate::Binders<T> {
let (v, b) = binders.into_value_and_skipped_binders();
crate::Binders::new(b, from_chalk(db, v))
}
}
impl ToChalk for crate::ConstrainedSubst {
type Chalk = chalk_ir::ConstrainedSubst<Interner>;
fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk {
unimplemented!()
}
fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
ConstrainedSubst { subst: from_chalk(db, chalk.subst) }
}
}
pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
where
T: HasInterner<Interner = Interner>,
{
chalk_ir::Binders::new(
chalk_ir::VariableKinds::from_iter(
&Interner,
std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
.take(num_vars),
),
value,
)
}
pub(super) fn convert_where_clauses(
db: &dyn HirDatabase,
def: GenericDefId,
@ -493,7 +78,7 @@ pub(super) fn convert_where_clauses(
let generic_predicates = db.generic_predicates(def);
let mut result = Vec::with_capacity(generic_predicates.len());
for pred in generic_predicates.iter() {
result.push(pred.clone().substitute(&Interner, substs).to_chalk(db));
result.push(pred.clone().substitute(&Interner, substs));
}
result
}
@ -505,7 +90,7 @@ pub(super) fn generic_predicate_to_inline_bound(
) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> {
// An InlineBound is like a GenericPredicate, except the self type is left out.
// We don't have a special type for this, but Chalk does.
let self_ty_shifted_in = self_ty.clone().shifted_in_from(DebruijnIndex::ONE);
let self_ty_shifted_in = self_ty.clone().shifted_in_from(&Interner, DebruijnIndex::ONE);
let (pred, binders) = pred.as_ref().into_value_and_skipped_binders();
match pred {
WhereClause::Implemented(trait_ref) => {
@ -516,7 +101,7 @@ pub(super) fn generic_predicate_to_inline_bound(
}
let args_no_self = trait_ref.substitution.interned()[1..]
.iter()
.map(|ty| ty.clone().to_chalk(db).cast(&Interner))
.map(|ty| ty.clone().cast(&Interner))
.collect();
let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
@ -528,10 +113,10 @@ pub(super) fn generic_predicate_to_inline_bound(
let trait_ = projection_ty.trait_(db);
let args_no_self = projection_ty.substitution.interned()[1..]
.iter()
.map(|ty| ty.clone().to_chalk(db).cast(&Interner))
.map(|ty| ty.clone().cast(&Interner))
.collect();
let alias_eq_bound = rust_ir::AliasEqBound {
value: ty.clone().to_chalk(db),
value: ty.clone(),
trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self },
associated_ty_id: projection_ty.associated_ty_id,
parameters: Vec::new(), // FIXME we don't support generic associated types yet

View file

@ -1,549 +0,0 @@
//! This is the home of `Ty` etc. until they get replaced by their chalk_ir
//! equivalents.
use std::sync::Arc;
use chalk_ir::{
cast::{Cast, CastTo, Caster},
BoundVar, Mutability, Scalar, TyVariableKind,
};
use smallvec::SmallVec;
use crate::{
AssocTypeId, CanonicalVarKinds, ChalkTraitId, ClosureId, Const, FnDefId, FnSig, ForeignDefId,
Interner, Lifetime, OpaqueTyId, PlaceholderIndex, TypeWalk, VariableKind, VariableKinds,
};
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct OpaqueTy {
pub opaque_ty_id: OpaqueTyId,
pub substitution: Substitution,
}
/// A "projection" type corresponds to an (unnormalized)
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
/// trait and all its parameters are fully known.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct ProjectionTy {
pub associated_ty_id: AssocTypeId,
pub substitution: Substitution,
}
impl ProjectionTy {
pub fn self_type_parameter(&self, interner: &Interner) -> Ty {
self.substitution.interned()[0].assert_ty_ref(interner).clone()
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct DynTy {
/// The unknown self type.
pub bounds: Binders<QuantifiedWhereClauses>,
pub lifetime: Lifetime,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct FnPointer {
pub num_binders: usize,
pub sig: FnSig,
pub substitution: FnSubst,
}
/// A wrapper for the substs on a Fn.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct FnSubst(pub Substitution);
impl FnPointer {
/// Represent the current `Fn` as if it was wrapped in `Binders`
pub fn into_binders(self, interner: &Interner) -> Binders<FnSubst> {
Binders::new(
VariableKinds::from_iter(
interner,
(0..self.num_binders).map(|_| VariableKind::Lifetime),
),
self.substitution,
)
}
/// Represent the current `Fn` as if it was wrapped in `Binders`
pub fn as_binders(&self, interner: &Interner) -> Binders<&FnSubst> {
Binders::new(
VariableKinds::from_iter(
interner,
(0..self.num_binders).map(|_| VariableKind::Lifetime),
),
&self.substitution,
)
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum AliasTy {
/// A "projection" type corresponds to an (unnormalized)
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
/// trait and all its parameters are fully known.
Projection(ProjectionTy),
/// An opaque type (`impl Trait`).
///
/// This is currently only used for return type impl trait; each instance of
/// `impl Trait` in a return type gets its own ID.
Opaque(OpaqueTy),
}
/// A type.
///
/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
/// the same thing (but in a different way).
///
/// This should be cheap to clone.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum TyKind {
/// Structures, enumerations and unions.
Adt(chalk_ir::AdtId<Interner>, Substitution),
/// Represents an associated item like `Iterator::Item`. This is used
/// when we have tried to normalize a projection like `T::Item` but
/// couldn't find a better representation. In that case, we generate
/// an **application type** like `(Iterator::Item)<T>`.
AssociatedType(AssocTypeId, Substitution),
/// a scalar type like `bool` or `u32`
Scalar(Scalar),
/// A tuple type. For example, `(i32, bool)`.
Tuple(usize, Substitution),
/// An array with the given length. Written as `[T; n]`.
Array(Ty, Const),
/// The pointee of an array slice. Written as `[T]`.
Slice(Ty),
/// A raw pointer. Written as `*mut T` or `*const T`
Raw(Mutability, Ty),
/// A reference; a pointer with an associated lifetime. Written as
/// `&'a mut T` or `&'a T`.
Ref(Mutability, Lifetime, Ty),
/// This represents a placeholder for an opaque type in situations where we
/// don't know the hidden type (i.e. currently almost always). This is
/// analogous to the `AssociatedType` type constructor.
/// It is also used as the type of async block, with one type parameter
/// representing the Future::Output type.
OpaqueType(OpaqueTyId, Substitution),
/// The anonymous type of a function declaration/definition. Each
/// function has a unique type, which is output (for a function
/// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
///
/// This includes tuple struct / enum variant constructors as well.
///
/// For example the type of `bar` here:
///
/// ```
/// fn foo() -> i32 { 1 }
/// let bar = foo; // bar: fn() -> i32 {foo}
/// ```
FnDef(FnDefId, Substitution),
/// The pointee of a string slice. Written as `str`.
Str,
/// The never type `!`.
Never,
/// The type of a specific closure.
///
/// The closure signature is stored in a `FnPtr` type in the first type
/// parameter.
Closure(ClosureId, Substitution),
/// Represents a foreign type declared in external blocks.
Foreign(ForeignDefId),
/// A pointer to a function. Written as `fn() -> i32`.
///
/// For example the type of `bar` here:
///
/// ```
/// fn foo() -> i32 { 1 }
/// let bar: fn() -> i32 = foo;
/// ```
Function(FnPointer),
/// An "alias" type represents some form of type alias, such as:
/// - An associated type projection like `<T as Iterator>::Item`
/// - `impl Trait` types
/// - Named type aliases like `type Foo<X> = Vec<X>`
Alias(AliasTy),
/// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
/// {}` when we're type-checking the body of that function. In this
/// situation, we know this stands for *some* type, but don't know the exact
/// type.
Placeholder(PlaceholderIndex),
/// A bound type variable. This is used in various places: when representing
/// some polymorphic type like the type of function `fn f<T>`, the type
/// parameters get turned into variables; during trait resolution, inference
/// variables get turned into bound variables and back; and in `Dyn` the
/// `Self` type is represented with a bound variable as well.
BoundVar(BoundVar),
/// A type variable used during type checking.
InferenceVar(InferenceVar, TyVariableKind),
/// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
///
/// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)`
/// represents the `Self` type inside the bounds. This is currently
/// implicit; Chalk has the `Binders` struct to make it explicit, but it
/// didn't seem worth the overhead yet.
Dyn(DynTy),
/// A placeholder for a type which could not be computed; this is propagated
/// to avoid useless error messages. Doubles as a placeholder where type
/// variables are inserted before type checking, since we want to try to
/// infer a better type here anyway -- for the IDE use case, we want to try
/// to infer as much as possible even in the presence of type errors.
Error,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Ty(Arc<TyKind>);
impl TyKind {
pub fn intern(self, _interner: &Interner) -> Ty {
Ty(Arc::new(self))
}
}
impl Ty {
pub fn kind(&self, _interner: &Interner) -> &TyKind {
&self.0
}
pub fn interned_mut(&mut self) -> &mut TyKind {
Arc::make_mut(&mut self.0)
}
pub fn into_inner(self) -> TyKind {
Arc::try_unwrap(self.0).unwrap_or_else(|a| (*a).clone())
}
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct GenericArg {
interned: GenericArgData,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum GenericArgData {
Ty(Ty),
}
impl GenericArg {
/// Constructs a generic argument using `GenericArgData`.
pub fn new(_interner: &Interner, data: GenericArgData) -> Self {
GenericArg { interned: data }
}
/// Gets the interned value.
pub fn interned(&self) -> &GenericArgData {
&self.interned
}
/// Asserts that this is a type argument.
pub fn assert_ty_ref(&self, interner: &Interner) -> &Ty {
self.ty(interner).unwrap()
}
/// Checks whether the generic argument is a type.
pub fn is_ty(&self, _interner: &Interner) -> bool {
match self.interned() {
GenericArgData::Ty(_) => true,
}
}
/// Returns the type if it is one, `None` otherwise.
pub fn ty(&self, _interner: &Interner) -> Option<&Ty> {
match self.interned() {
GenericArgData::Ty(t) => Some(t),
}
}
pub fn interned_mut(&mut self) -> &mut GenericArgData {
&mut self.interned
}
}
/// A list of substitutions for generic parameters.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Substitution(SmallVec<[GenericArg; 2]>);
impl Substitution {
pub fn interned(&self) -> &SmallVec<[GenericArg; 2]> {
&self.0
}
pub fn len(&self, _: &Interner) -> usize {
self.0.len()
}
pub fn is_empty(&self, _: &Interner) -> bool {
self.0.is_empty()
}
pub fn at(&self, _: &Interner, i: usize) -> &GenericArg {
&self.0[i]
}
pub fn empty(_: &Interner) -> Substitution {
Substitution(SmallVec::new())
}
pub fn iter(&self, _: &Interner) -> std::slice::Iter<'_, GenericArg> {
self.0.iter()
}
pub fn from1(_interner: &Interner, ty: Ty) -> Substitution {
Substitution::intern({
let mut v = SmallVec::new();
v.push(ty.cast(&Interner));
v
})
}
pub fn from_iter(
interner: &Interner,
elements: impl IntoIterator<Item = impl CastTo<GenericArg>>,
) -> Self {
Substitution(elements.into_iter().casted(interner).collect())
}
pub fn apply<T: TypeWalk>(&self, value: T, _interner: &Interner) -> T {
value.subst_bound_vars(self)
}
// Temporary helper functions, to be removed
pub fn intern(interned: SmallVec<[GenericArg; 2]>) -> Substitution {
Substitution(interned)
}
pub fn interned_mut(&mut self) -> &mut SmallVec<[GenericArg; 2]> {
&mut self.0
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Binders<T> {
/// The binders that quantify over the value.
pub binders: VariableKinds,
value: T,
}
impl<T> Binders<T> {
pub fn new(binders: VariableKinds, value: T) -> Self {
Self { binders, value }
}
pub fn empty(_interner: &Interner, value: T) -> Self {
crate::make_only_type_binders(0, value)
}
pub fn as_ref(&self) -> Binders<&T> {
Binders { binders: self.binders.clone(), value: &self.value }
}
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> {
Binders { binders: self.binders, value: f(self.value) }
}
pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> {
Some(Binders { binders: self.binders, value: f(self.value)? })
}
pub fn skip_binders(&self) -> &T {
&self.value
}
pub fn into_value_and_skipped_binders(self) -> (T, VariableKinds) {
(self.value, self.binders)
}
/// Returns the number of binders.
pub fn len(&self, interner: &Interner) -> usize {
self.binders.len(interner)
}
// Temporary helper function, to be removed
pub fn skip_binders_mut(&mut self) -> &mut T {
&mut self.value
}
}
impl<T: Clone> Binders<&T> {
pub fn cloned(&self) -> Binders<T> {
Binders::new(self.binders.clone(), self.value.clone())
}
}
impl<T: TypeWalk> Binders<T> {
/// Substitutes all variables.
pub fn substitute(self, interner: &Interner, subst: &Substitution) -> T {
let (value, binders) = self.into_value_and_skipped_binders();
assert_eq!(subst.len(interner), binders.len(interner));
value.subst_bound_vars(subst)
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for Binders<T> {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
let Binders { ref binders, ref value } = *self;
write!(fmt, "for{:?} ", binders.inner_debug(&Interner))?;
std::fmt::Debug::fmt(value, fmt)
}
}
/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TraitRef {
pub trait_id: ChalkTraitId,
pub substitution: Substitution,
}
impl TraitRef {
pub fn self_type_parameter(&self, interner: &Interner) -> Ty {
self.substitution.at(interner, 0).assert_ty_ref(interner).clone()
}
}
/// Like `generics::WherePredicate`, but with resolved types: A condition on the
/// parameters of a generic item.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum WhereClause {
/// The given trait needs to be implemented for its type parameters.
Implemented(TraitRef),
/// An associated type bindings like in `Iterator<Item = T>`.
AliasEq(AliasEq),
}
pub type QuantifiedWhereClause = Binders<WhereClause>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct QuantifiedWhereClauses(Arc<[QuantifiedWhereClause]>);
impl QuantifiedWhereClauses {
pub fn from_iter(
_interner: &Interner,
elements: impl IntoIterator<Item = QuantifiedWhereClause>,
) -> Self {
QuantifiedWhereClauses(elements.into_iter().collect())
}
pub fn interned(&self) -> &Arc<[QuantifiedWhereClause]> {
&self.0
}
pub fn interned_mut(&mut self) -> &mut Arc<[QuantifiedWhereClause]> {
&mut self.0
}
}
/// Basically a claim (currently not validated / checked) that the contained
/// type / trait ref contains no inference variables; any inference variables it
/// contained have been replaced by bound variables, and `kinds` tells us how
/// many there are and whether they were normal or float/int variables. This is
/// used to erase irrelevant differences between types before using them in
/// queries.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Canonical<T> {
pub value: T,
pub binders: CanonicalVarKinds,
}
/// Something (usually a goal), along with an environment.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct InEnvironment<T> {
pub environment: chalk_ir::Environment<Interner>,
pub goal: T,
}
impl<T> InEnvironment<T> {
pub fn new(environment: &chalk_ir::Environment<Interner>, value: T) -> InEnvironment<T> {
InEnvironment { environment: environment.clone(), goal: value }
}
}
/// Something that needs to be proven (by Chalk) during type checking, e.g. that
/// a certain type implements a certain trait. Proving the Obligation might
/// result in additional information about inference variables.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum DomainGoal {
Holds(WhereClause),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AliasEq {
pub alias: AliasTy,
pub ty: Ty,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ConstrainedSubst {
pub subst: Substitution,
}
#[derive(Clone, Debug, PartialEq, Eq)]
/// A (possible) solution for a proposed goal.
pub enum Solution {
/// The goal indeed holds, and there is a unique value for all existential
/// variables.
Unique(Canonical<ConstrainedSubst>),
/// The goal may be provable in multiple ways, but regardless we may have some guidance
/// for type inference. In this case, we don't return any lifetime
/// constraints, since we have not "committed" to any particular solution
/// yet.
Ambig(Guidance),
}
#[derive(Clone, Debug, PartialEq, Eq)]
/// When a goal holds ambiguously (e.g., because there are multiple possible
/// solutions), we issue a set of *guidance* back to type inference.
pub enum Guidance {
/// The existential variables *must* have the given values if the goal is
/// ever to hold, but that alone isn't enough to guarantee the goal will
/// actually hold.
Definite(Canonical<Substitution>),
/// There are multiple plausible values for the existentials, but the ones
/// here are suggested as the preferred choice heuristically. These should
/// be used for inference fallback only.
Suggested(Canonical<Substitution>),
/// There's no useful information to feed back to type inference
Unknown,
}
/// The kinds of placeholders we need during type inference. There's separate
/// values for general types, and for integer and float variables. The latter
/// two are used for inference of literal values (e.g. `100` could be one of
/// several integer types).
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct InferenceVar {
index: u32,
}
impl From<u32> for InferenceVar {
fn from(index: u32) -> InferenceVar {
InferenceVar { index }
}
}
impl InferenceVar {
/// Gets the underlying index value.
pub fn index(self) -> u32 {
self.index
}
}

View file

@ -1,8 +1,7 @@
//! Helper functions for working with def, which don't need to be a separate
//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
use std::sync::Arc;
use chalk_ir::{BoundVar, DebruijnIndex};
use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
use hir_def::{
db::DefDatabase,
generics::{
@ -16,9 +15,7 @@ use hir_def::{
};
use hir_expand::name::{name, Name};
use crate::{
db::HirDatabase, Interner, Substitution, TraitRef, TraitRefExt, TyKind, TypeWalk, WhereClause,
};
use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TraitRefExt, TyKind, WhereClause};
fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
let resolver = trait_.resolver(db);
@ -69,7 +66,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
// FIXME: how to correctly handle higher-ranked bounds here?
WhereClause::Implemented(tr) => Some(
tr.clone()
.shifted_out_to(DebruijnIndex::ONE)
.shifted_out_to(&Interner, DebruijnIndex::ONE)
.expect("FIXME unexpected higher-ranked trait bound"),
),
_ => None,
@ -137,15 +134,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
})
}
/// Helper for mutating `Arc<[T]>` (i.e. `Arc::make_mut` for Arc slices).
/// The underlying values are cloned if there are other strong references.
pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
if Arc::get_mut(a).is_none() {
*a = a.iter().cloned().collect();
}
Arc::get_mut(a).unwrap()
}
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)));
Generics { def, params: db.generic_params(def), parent_generics }

View file

@ -1,138 +1,17 @@
//! The `TypeWalk` trait (probably to be replaced by Chalk's `Fold` and
//! `Visit`).
use std::mem;
use chalk_ir::DebruijnIndex;
use chalk_ir::interner::HasInterner;
use crate::{
utils::make_mut_slice, AliasEq, AliasTy, Binders, CallableSig, FnSubst, GenericArg,
GenericArgData, Interner, OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind,
WhereClause,
AliasEq, AliasTy, Binders, CallableSig, FnSubst, GenericArg, GenericArgData, Interner,
OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind, WhereClause,
};
/// This allows walking structures that contain types to do something with those
/// types, similar to Chalk's `Fold` trait.
pub trait TypeWalk {
fn walk(&self, f: &mut impl FnMut(&Ty));
fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
self.walk_mut_binders(&mut |ty, _binders| f(ty), DebruijnIndex::INNERMOST);
}
/// Walk the type, counting entered binders.
///
/// `TyKind::Bound` variables use DeBruijn indexing, which means that 0 refers
/// to the innermost binder, 1 to the next, etc.. So when we want to
/// substitute a certain bound variable, we can't just walk the whole type
/// and blindly replace each instance of a certain index; when we 'enter'
/// things that introduce new bound variables, we have to keep track of
/// that. Currently, the only thing that introduces bound variables on our
/// side are `TyKind::Dyn` and `TyKind::Opaque`, which each introduce a bound
/// variable for the self type.
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
);
fn fold_binders(
mut self,
f: &mut impl FnMut(Ty, DebruijnIndex) -> Ty,
binders: DebruijnIndex,
) -> Self
where
Self: Sized,
{
self.walk_mut_binders(
&mut |ty_mut, binders| {
let ty = mem::replace(ty_mut, TyKind::Error.intern(&Interner));
*ty_mut = f(ty, binders);
},
binders,
);
self
}
fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
where
Self: Sized,
{
self.walk_mut(&mut |ty_mut| {
let ty = mem::replace(ty_mut, TyKind::Error.intern(&Interner));
*ty_mut = f(ty);
});
self
}
/// Substitutes `TyKind::Bound` vars with the given substitution.
fn subst_bound_vars(self, substs: &Substitution) -> Self
where
Self: Sized,
{
self.subst_bound_vars_at_depth(substs, DebruijnIndex::INNERMOST)
}
/// Substitutes `TyKind::Bound` vars with the given substitution.
fn subst_bound_vars_at_depth(mut self, substs: &Substitution, depth: DebruijnIndex) -> Self
where
Self: Sized,
{
self.walk_mut_binders(
&mut |ty, binders| {
if let &mut TyKind::BoundVar(bound) = ty.interned_mut() {
if bound.debruijn >= binders {
*ty = substs.interned()[bound.index]
.assert_ty_ref(&Interner)
.clone()
.shifted_in_from(binders);
}
}
},
depth,
);
self
}
fn shifted_in(self, _interner: &Interner) -> Self
where
Self: Sized,
{
self.shifted_in_from(DebruijnIndex::ONE)
}
/// Shifts up debruijn indices of `TyKind::Bound` vars by `n`.
fn shifted_in_from(self, n: DebruijnIndex) -> Self
where
Self: Sized,
{
self.fold_binders(
&mut |ty, binders| match ty.kind(&Interner) {
TyKind::BoundVar(bound) if bound.debruijn >= binders => {
TyKind::BoundVar(bound.shifted_in_from(n)).intern(&Interner)
}
_ => ty,
},
DebruijnIndex::INNERMOST,
)
}
/// Shifts debruijn indices of `TyKind::Bound` vars out (down) by `n`.
fn shifted_out_to(self, n: DebruijnIndex) -> Option<Self>
where
Self: Sized + std::fmt::Debug,
{
Some(self.fold_binders(
&mut |ty, binders| {
match ty.kind(&Interner) {
TyKind::BoundVar(bound) if bound.debruijn >= binders => {
TyKind::BoundVar(bound.shifted_out_to(n).unwrap_or(bound.clone()))
.intern(&Interner)
}
_ => ty,
}
},
DebruijnIndex::INNERMOST,
))
}
}
impl TypeWalk for Ty {
@ -174,45 +53,6 @@ impl TypeWalk for Ty {
}
f(self);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self.interned_mut() {
TyKind::Alias(AliasTy::Projection(p_ty)) => {
p_ty.substitution.walk_mut_binders(f, binders);
}
TyKind::Dyn(dyn_ty) => {
for p in make_mut_slice(dyn_ty.bounds.skip_binders_mut().interned_mut()) {
p.walk_mut_binders(f, binders.shifted_in());
}
}
TyKind::Alias(AliasTy::Opaque(o_ty)) => {
o_ty.substitution.walk_mut_binders(f, binders);
}
TyKind::Slice(ty)
| TyKind::Array(ty, _)
| TyKind::Ref(_, _, ty)
| TyKind::Raw(_, ty) => {
ty.walk_mut_binders(f, binders);
}
TyKind::Function(fn_pointer) => {
fn_pointer.substitution.0.walk_mut_binders(f, binders.shifted_in());
}
TyKind::Adt(_, substs)
| TyKind::FnDef(_, substs)
| TyKind::Tuple(_, substs)
| TyKind::OpaqueType(_, substs)
| TyKind::AssociatedType(_, substs)
| TyKind::Closure(.., substs) => {
substs.walk_mut_binders(f, binders);
}
_ => {}
}
f(self, binders);
}
}
impl<T: TypeWalk> TypeWalk for Vec<T> {
@ -221,43 +61,18 @@ impl<T: TypeWalk> TypeWalk for Vec<T> {
t.walk(f);
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
for t in self {
t.walk_mut_binders(f, binders);
}
}
}
impl TypeWalk for OpaqueTy {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.substitution.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substitution.walk_mut_binders(f, binders);
}
}
impl TypeWalk for ProjectionTy {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.substitution.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substitution.walk_mut_binders(f, binders);
}
}
impl TypeWalk for AliasTy {
@ -267,17 +82,6 @@ impl TypeWalk for AliasTy {
AliasTy::Opaque(it) => it.walk(f),
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self {
AliasTy::Projection(it) => it.walk_mut_binders(f, binders),
AliasTy::Opaque(it) => it.walk_mut_binders(f, binders),
}
}
}
impl TypeWalk for GenericArg {
@ -286,18 +90,7 @@ impl TypeWalk for GenericArg {
GenericArgData::Ty(ty) => {
ty.walk(f);
}
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self.interned_mut() {
GenericArgData::Ty(ty) => {
ty.walk_mut_binders(f, binders);
}
_ => {}
}
}
}
@ -308,44 +101,18 @@ impl TypeWalk for Substitution {
t.walk(f);
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
for t in self.interned_mut() {
t.walk_mut_binders(f, binders);
}
}
}
impl<T: TypeWalk> TypeWalk for Binders<T> {
impl<T: TypeWalk + HasInterner<Interner = Interner>> TypeWalk for Binders<T> {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.skip_binders().walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.skip_binders_mut().walk_mut_binders(f, binders.shifted_in())
}
}
impl TypeWalk for TraitRef {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.substitution.walk(f);
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substitution.walk_mut_binders(f, binders);
}
}
impl TypeWalk for WhereClause {
@ -353,17 +120,7 @@ impl TypeWalk for WhereClause {
match self {
WhereClause::Implemented(trait_ref) => trait_ref.walk(f),
WhereClause::AliasEq(alias_eq) => alias_eq.walk(f),
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
match self {
WhereClause::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
WhereClause::AliasEq(alias_eq) => alias_eq.walk_mut_binders(f, binders),
_ => {}
}
}
}
@ -374,16 +131,6 @@ impl TypeWalk for CallableSig {
t.walk(f);
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
for t in make_mut_slice(&mut self.params_and_return) {
t.walk_mut_binders(f, binders);
}
}
}
impl TypeWalk for AliasEq {
@ -394,30 +141,10 @@ impl TypeWalk for AliasEq {
AliasTy::Opaque(opaque) => opaque.walk(f),
}
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.ty.walk_mut_binders(f, binders);
match &mut self.alias {
AliasTy::Projection(projection_ty) => projection_ty.walk_mut_binders(f, binders),
AliasTy::Opaque(opaque) => opaque.walk_mut_binders(f, binders),
}
}
}
impl TypeWalk for FnSubst {
impl TypeWalk for FnSubst<Interner> {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.0.walk(f)
}
fn walk_mut_binders(
&mut self,
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.0.walk_mut_binders(f, binders)
}
}

View file

@ -22,7 +22,7 @@ env_logger = { version = "0.8.1", default-features = false }
itertools = "0.10.0"
jod-thread = "0.1.0"
log = "0.4.8"
lsp-types = { version = "0.88.0", features = ["proposed"] }
lsp-types = { version = "0.89.0", features = ["proposed"] }
parking_lot = "0.11.0"
xflags = "0.2.1"
oorandom = "11.1.2"