Skip to content

Use Chalk's built-in representations for fn items and pointers #4575

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/ra_hir_ty/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::interned]
fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId;
#[salsa::interned]
fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId;
#[salsa::interned]
fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
#[salsa::interned]
fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId;
Expand All @@ -94,6 +96,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::traits::chalk::impl_datum_query)]
fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>;

#[salsa::invoke(crate::traits::chalk::fn_def_datum_query)]
fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>;

#[salsa::invoke(crate::traits::chalk::associated_ty_value_query)]
fn associated_ty_value(
&self,
Expand Down
6 changes: 6 additions & 0 deletions crates/ra_hir_ty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ pub enum TypeCtor {
pub struct TypeCtorId(salsa::InternId);
impl_intern_key!(TypeCtorId);

/// 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)]
pub struct CallableDefId(salsa::InternId);
impl_intern_key!(CallableDefId);

impl TypeCtor {
pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize {
match self {
Expand Down
74 changes: 74 additions & 0 deletions crates/ra_hir_ty/src/tests/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2643,6 +2643,80 @@ fn test() {
);
}

#[test]
fn builtin_fn_def_copy() {
assert_snapshot!(
infer_with_mismatches(r#"
#[lang = "copy"]
trait Copy {}

fn foo() {}
fn bar<T: Copy>(T) -> T {}
struct Struct(usize);
enum Enum { Variant(usize) }

trait Test { fn test(&self) -> bool; }
impl<T: Copy> Test for T {}

fn test() {
foo.test();
bar.test();
Struct.test();
Enum::Variant.test();
}
"#, true),
// wrong result, because the built-in Copy impl for fn defs doesn't exist in Chalk yet
@r###"
42..44 '{}': ()
61..62 'T': {unknown}
69..71 '{}': ()
69..71: expected T, got ()
146..150 'self': &Self
202..282 '{ ...t(); }': ()
208..211 'foo': fn foo()
208..218 'foo.test()': {unknown}
224..227 'bar': fn bar<{unknown}>({unknown}) -> {unknown}
224..234 'bar.test()': {unknown}
240..246 'Struct': Struct(usize) -> Struct
240..253 'Struct.test()': {unknown}
259..272 'Enum::Variant': Variant(usize) -> Enum
259..279 'Enum::...test()': {unknown}
"###
);
}

#[test]
fn builtin_fn_ptr_copy() {
assert_snapshot!(
infer_with_mismatches(r#"
#[lang = "copy"]
trait Copy {}

trait Test { fn test(&self) -> bool; }
impl<T: Copy> Test for T {}

fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
f1.test();
f2.test();
f3.test();
}
"#, true),
@r###"
55..59 'self': &Self
109..111 'f1': fn()
119..121 'f2': fn(usize) -> u8
140..142 'f3': fn(u8, u8) -> &u8
163..211 '{ ...t(); }': ()
169..171 'f1': fn()
169..178 'f1.test()': bool
184..186 'f2': fn(usize) -> u8
184..193 'f2.test()': bool
199..201 'f3': fn(u8, u8) -> &u8
199..208 'f3.test()': bool
"###
);
}

#[test]
fn builtin_sized() {
assert_snapshot!(
Expand Down
39 changes: 35 additions & 4 deletions crates/ra_hir_ty/src/traits/chalk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use ra_db::{salsa::InternKey, CrateId};
use super::{builtin, AssocTyValue, ChalkContext, Impl};
use crate::{
db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor,
CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor,
};
use chalk_rust_ir::WellKnownTrait;
use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders};
Expand Down Expand Up @@ -54,10 +54,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {

fn fn_def_datum(
&self,
_fn_def_id: chalk_ir::FnDefId<Interner>,
fn_def_id: chalk_ir::FnDefId<Interner>,
) -> Arc<chalk_rust_ir::FnDefDatum<Interner>> {
// We don't yet provide any FnDefs to Chalk
unimplemented!()
self.db.fn_def_datum(self.krate, fn_def_id)
}

fn impls_for_trait(
Expand Down Expand Up @@ -405,6 +404,26 @@ fn type_alias_associated_ty_value(
Arc::new(value)
}

pub(crate) fn fn_def_datum_query(
db: &dyn HirDatabase,
_krate: CrateId,
fn_def_id: FnDefId,
) -> Arc<FnDefDatum> {
let callable_def: CallableDef = from_chalk(db, fn_def_id);
let generic_params = generics(db.upcast(), callable_def.into());
let sig = db.callable_item_signature(callable_def);
let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
let bound = chalk_rust_ir::FnDefDatumBound {
// Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
argument_types: sig.value.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(),
return_type: sig.value.ret().clone().to_chalk(db),
where_clauses,
};
let datum = FnDefDatum { id: fn_def_id, binders: make_binders(bound, sig.num_binders) };
Arc::new(datum)
}

impl From<AdtId> for crate::TypeCtorId {
fn from(struct_id: AdtId) -> Self {
struct_id.0
Expand All @@ -417,6 +436,18 @@ impl From<crate::TypeCtorId> for AdtId {
}
}

impl From<FnDefId> for crate::CallableDefId {
fn from(fn_def_id: FnDefId) -> Self {
InternKey::from_intern_id(fn_def_id.0)
}
}

impl From<crate::CallableDefId> for FnDefId {
fn from(callable_def_id: crate::CallableDefId) -> Self {
chalk_ir::FnDefId(callable_def_id.as_intern_id())
}
}

impl From<ImplId> for crate::traits::GlobalImplId {
fn from(impl_id: ImplId) -> Self {
InternKey::from_intern_id(impl_id.0)
Expand Down
2 changes: 2 additions & 0 deletions crates/ra_hir_ty/src/traits/chalk/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub type ImplId = chalk_ir::ImplId<Interner>;
pub type ImplDatum = chalk_rust_ir::ImplDatum<Interner>;
pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId<Interner>;
pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<Interner>;
pub type FnDefId = chalk_ir::FnDefId<Interner>;
pub type FnDefDatum = chalk_rust_ir::FnDefDatum<Interner>;

impl chalk_ir::interner::Interner for Interner {
type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc?
Expand Down
53 changes: 41 additions & 12 deletions crates/ra_hir_ty/src/traits/chalk/mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use crate::{
db::HirDatabase,
primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain},
traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
ApplicationTy, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, Substs,
TraitEnvironment, TraitRef, Ty, TypeCtor,
ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy,
Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
};

use super::interner::*;
Expand All @@ -26,14 +26,19 @@ impl ToChalk for Ty {
type Chalk = chalk_ir::Ty<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
match self {
Ty::Apply(apply_ty) => {
if let TypeCtor::Ref(m) = apply_ty.ctor {
return ref_to_chalk(db, m, apply_ty.parameters);
Ty::Apply(apply_ty) => match apply_ty.ctor {
TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters),
TypeCtor::FnPtr { num_args: _ } => {
let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner);
chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution })
.intern(&Interner)
}
let name = apply_ty.ctor.to_chalk(db);
let substitution = apply_ty.parameters.to_chalk(db);
chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
}
_ => {
let name = apply_ty.ctor.to_chalk(db);
let substitution = apply_ty.parameters.to_chalk(db);
chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner)
}
},
Ty::Projection(proj_ty) => {
let associated_ty_id = proj_ty.associated_ty.to_chalk(db);
let substitution = proj_ty.parameters.to_chalk(db);
Expand Down Expand Up @@ -93,7 +98,13 @@ impl ToChalk for Ty {
Ty::Projection(ProjectionTy { associated_ty, parameters })
}
chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(),
chalk_ir::TyData::Function(_) => unimplemented!(),
chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => {
let parameters: Substs = from_chalk(db, substitution);
Ty::Apply(ApplicationTy {
ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16 },
parameters,
})
}
chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx),
chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
chalk_ir::TyData::Dyn(where_clauses) => {
Expand Down Expand Up @@ -217,11 +228,14 @@ impl ToChalk for TypeCtor {
TypeCtor::Slice => TypeName::Slice,
TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)),
TypeCtor::Str => TypeName::Str,
TypeCtor::FnDef(callable_def) => {
let id = callable_def.to_chalk(db);
TypeName::FnDef(id)
}
TypeCtor::Int(Uncertain::Unknown)
| TypeCtor::Float(Uncertain::Unknown)
| TypeCtor::Adt(_)
| TypeCtor::Array
| TypeCtor::FnDef(_)
| TypeCtor::FnPtr { .. }
| TypeCtor::Never
| TypeCtor::Closure { .. } => {
Expand Down Expand Up @@ -260,7 +274,10 @@ impl ToChalk for TypeCtor {
TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)),
TypeName::Str => TypeCtor::Str,

TypeName::FnDef(_) => unreachable!(),
TypeName::FnDef(fn_def_id) => {
let callable_def = from_chalk(db, fn_def_id);
TypeCtor::FnDef(callable_def)
}

TypeName::Error => {
// this should not be reached, since we don't represent TypeName::Error with TypeCtor
Expand Down Expand Up @@ -347,6 +364,18 @@ impl ToChalk for Impl {
}
}

impl ToChalk for CallableDef {
type Chalk = FnDefId;

fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
db.intern_callable_def(self).into()
}

fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDef {
db.lookup_intern_callable_def(fn_def_id.into())
}
}

impl ToChalk for TypeAliasId {
type Chalk = AssocTypeId;

Expand Down
18 changes: 16 additions & 2 deletions crates/ra_hir_ty/src/traits/chalk/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,24 @@ impl DebugContext<'_> {

pub fn debug_fn_def_id(
&self,
_fn_def_id: chalk_ir::FnDefId<Interner>,
fn_def_id: chalk_ir::FnDefId<Interner>,
fmt: &mut fmt::Formatter<'_>,
) -> Result<(), fmt::Error> {
write!(fmt, "fn")
let def: CallableDef = from_chalk(self.0, fn_def_id);
let name = match def {
CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(),
CallableDef::StructId(s) => self.0.struct_data(s).name.clone(),
CallableDef::EnumVariantId(e) => {
let enum_data = self.0.enum_data(e.parent);
enum_data.variants[e.local_id].name.clone()
}
};
match def {
CallableDef::FunctionId(_) => write!(fmt, "{{fn {}}}", name),
CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {
write!(fmt, "{{ctor {}}}", name)
}
}
}

pub fn debug_const(
Expand Down