From e81c76a95ae180e7c5cf2d5af3658cbfc2d8b4ef Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 18 May 2020 21:25:23 +0200 Subject: Use Chalk's built-in representations of primitive types For references, we make sure Chalk actually gets a lifetime here. --- crates/ra_hir_ty/src/traits/chalk.rs | 170 ++++++++++++++++++++++++++++++++--- 1 file changed, 160 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index c2d7abd17..b80b67a7a 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -5,10 +5,13 @@ use log::debug; use chalk_ir::{ cast::Cast, fold::shift::Shift, interner::HasInterner, GenericArg, Goal, GoalData, - PlaceholderIndex, TypeName, UniverseIndex, + PlaceholderIndex, Scalar, TypeName, UniverseIndex, }; -use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId}; +use hir_def::{ + type_ref::Mutability, AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, + TypeAliasId, +}; use ra_db::{ salsa::{InternId, InternKey}, CrateId, @@ -16,7 +19,11 @@ use ra_db::{ use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; use crate::{ - db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, + db::HirDatabase, + display::HirDisplay, + method_resolution::TyFingerprint, + primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, + utils::generics, ApplicationTy, DebruijnIndex, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, }; @@ -330,6 +337,9 @@ impl ToChalk for Ty { fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty { match self { Ty::Apply(apply_ty) => { + if let TypeCtor::Ref(m) = apply_ty.ctor { + return ref_to_chalk(db, m, apply_ty.parameters); + } 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) @@ -373,6 +383,7 @@ impl ToChalk for Ty { match chalk.data(&Interner).clone() { chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name { TypeName::Error => Ty::Unknown, + TypeName::Ref(m) => ref_from_chalk(db, m, apply_ty.substitution), _ => { let ctor = from_chalk(db, apply_ty.name); let parameters = from_chalk(db, apply_ty.substitution); @@ -409,6 +420,41 @@ impl ToChalk for Ty { } } +const LIFETIME_PLACEHOLDER: PlaceholderIndex = + PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::MAX }; + +/// We currently don't model lifetimes, but Chalk does. So, we have to insert a +/// fake lifetime here, because Chalks built-in logic may expect it to be there. +fn ref_to_chalk( + db: &dyn HirDatabase, + mutability: Mutability, + subst: Substs, +) -> chalk_ir::Ty { + let arg = subst[0].clone().to_chalk(db); + let lifetime = LIFETIME_PLACEHOLDER.to_lifetime(&Interner); + chalk_ir::ApplicationTy { + name: TypeName::Ref(mutability.to_chalk(db)), + substitution: chalk_ir::Substitution::from( + &Interner, + vec![lifetime.cast(&Interner), arg.cast(&Interner)], + ), + } + .intern(&Interner) +} + +/// Here we remove the lifetime from the type we got from Chalk. +fn ref_from_chalk( + db: &dyn HirDatabase, + mutability: chalk_ir::Mutability, + subst: chalk_ir::Substitution, +) -> Ty { + let tys = subst + .iter(&Interner) + .filter_map(|p| Some(from_chalk(db, p.ty(&Interner)?.clone()))) + .collect(); + Ty::apply(TypeCtor::Ref(from_chalk(db, mutability)), Substs(tys)) +} + impl ToChalk for Substs { type Chalk = chalk_ir::Substitution; @@ -465,7 +511,31 @@ impl ToChalk for TypeCtor { let type_id = type_alias.to_chalk(db); TypeName::AssociatedType(type_id) } - _ => { + + TypeCtor::Bool => TypeName::Scalar(Scalar::Bool), + TypeCtor::Char => TypeName::Scalar(Scalar::Char), + TypeCtor::Int(Uncertain::Known(int_ty)) => TypeName::Scalar(int_ty_to_chalk(int_ty)), + TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) => { + TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) + } + TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) => { + TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) + } + + TypeCtor::Tuple { cardinality } => TypeName::Tuple(cardinality.into()), + TypeCtor::RawPtr(mutability) => TypeName::Raw(mutability.to_chalk(db)), + TypeCtor::Slice => TypeName::Slice, + TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)), + TypeCtor::Str => TypeName::Str, + + TypeCtor::Int(Uncertain::Unknown) + | TypeCtor::Float(Uncertain::Unknown) + | TypeCtor::Adt(_) + | TypeCtor::Array + | TypeCtor::FnDef(_) + | TypeCtor::FnPtr { .. } + | TypeCtor::Never + | TypeCtor::Closure { .. } => { // other TypeCtors get interned and turned into a chalk StructId let struct_id = db.intern_type_ctor(self).into(); TypeName::Adt(struct_id) @@ -479,12 +549,27 @@ impl ToChalk for TypeCtor { TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), TypeName::OpaqueType(_) => unreachable!(), - TypeName::Scalar(_) => unreachable!(), - TypeName::Tuple(_) => unreachable!(), - TypeName::Raw(_) => unreachable!(), - TypeName::Slice => unreachable!(), - TypeName::Ref(_) => unreachable!(), - TypeName::Str => unreachable!(), + TypeName::Scalar(Scalar::Bool) => TypeCtor::Bool, + TypeName::Scalar(Scalar::Char) => TypeCtor::Char, + TypeName::Scalar(Scalar::Int(int_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { + signedness: Signedness::Signed, + bitness: bitness_from_chalk_int(int_ty), + })), + TypeName::Scalar(Scalar::Uint(uint_ty)) => TypeCtor::Int(Uncertain::Known(IntTy { + signedness: Signedness::Unsigned, + bitness: bitness_from_chalk_uint(uint_ty), + })), + TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F32)) => { + TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X32 })) + } + TypeName::Scalar(Scalar::Float(chalk_ir::FloatTy::F64)) => { + TypeCtor::Float(Uncertain::Known(FloatTy { bitness: FloatBitness::X64 })) + } + TypeName::Tuple(cardinality) => TypeCtor::Tuple { cardinality: cardinality as u16 }, + TypeName::Raw(mutability) => TypeCtor::RawPtr(from_chalk(db, mutability)), + TypeName::Slice => TypeCtor::Slice, + TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)), + TypeName::Str => TypeCtor::Str, TypeName::FnDef(_) => unreachable!(), @@ -496,6 +581,71 @@ impl ToChalk for TypeCtor { } } +fn bitness_from_chalk_uint(uint_ty: chalk_ir::UintTy) -> IntBitness { + use chalk_ir::UintTy; + + match uint_ty { + UintTy::Usize => IntBitness::Xsize, + UintTy::U8 => IntBitness::X8, + UintTy::U16 => IntBitness::X16, + UintTy::U32 => IntBitness::X32, + UintTy::U64 => IntBitness::X64, + UintTy::U128 => IntBitness::X128, + } +} + +fn bitness_from_chalk_int(int_ty: chalk_ir::IntTy) -> IntBitness { + use chalk_ir::IntTy; + + match int_ty { + IntTy::Isize => IntBitness::Xsize, + IntTy::I8 => IntBitness::X8, + IntTy::I16 => IntBitness::X16, + IntTy::I32 => IntBitness::X32, + IntTy::I64 => IntBitness::X64, + IntTy::I128 => IntBitness::X128, + } +} + +fn int_ty_to_chalk(int_ty: IntTy) -> Scalar { + use chalk_ir::{IntTy, UintTy}; + + match int_ty.signedness { + Signedness::Signed => Scalar::Int(match int_ty.bitness { + IntBitness::Xsize => IntTy::Isize, + IntBitness::X8 => IntTy::I8, + IntBitness::X16 => IntTy::I16, + IntBitness::X32 => IntTy::I32, + IntBitness::X64 => IntTy::I64, + IntBitness::X128 => IntTy::I128, + }), + Signedness::Unsigned => Scalar::Uint(match int_ty.bitness { + IntBitness::Xsize => UintTy::Usize, + IntBitness::X8 => UintTy::U8, + IntBitness::X16 => UintTy::U16, + IntBitness::X32 => UintTy::U32, + IntBitness::X64 => UintTy::U64, + IntBitness::X128 => UintTy::U128, + }), + } +} + +impl ToChalk for Mutability { + type Chalk = chalk_ir::Mutability; + fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk { + match self { + Mutability::Shared => chalk_ir::Mutability::Not, + Mutability::Mut => chalk_ir::Mutability::Mut, + } + } + fn from_chalk(_db: &dyn HirDatabase, chalk: Self::Chalk) -> Self { + match chalk { + chalk_ir::Mutability::Mut => Mutability::Mut, + chalk_ir::Mutability::Not => Mutability::Shared, + } + } +} + impl ToChalk for Impl { type Chalk = ImplId; -- cgit v1.2.3