Skip to content

Commit bf7d38c

Browse files
committed
Add TypeFlags for TyKind in chalk-ir
1 parent 70e77f1 commit bf7d38c

File tree

6 files changed

+276
-3
lines changed

6 files changed

+276
-3
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

chalk-integration/src/test_macros.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,11 @@ macro_rules! lifetime {
119119
lifetime!($($b)*)
120120
};
121121
}
122+
123+
#[macro_export]
124+
macro_rules! empty_substitution {
125+
() => {
126+
chalk_ir::Substitution::from_iter(&chalk_integration::interner::ChalkIr,
127+
Vec::<chalk_ir::GenericArg<chalk_integration::interner::ChalkIr>>::new());
128+
};
129+
}

chalk-ir/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ edition = "2018"
1111

1212
[dependencies]
1313
lazy_static = "1.4.0"
14+
bitflags = "1.2.1"
1415
chalk-derive = { version = "0.36.0-dev.0", path = "../chalk-derive" }

chalk-ir/src/lib.rs

Lines changed: 163 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ use chalk_derive::{Fold, HasInterner, SuperVisit, Visit, Zip};
1414
use std::marker::PhantomData;
1515

1616
pub use crate::debug::SeparatorTraitRef;
17-
17+
#[macro_use(bitflags)]
18+
extern crate bitflags;
1819
/// Uninhabited (empty) type, used in combination with `PhantomData`.
1920
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2021
pub enum Void {}
@@ -327,11 +328,121 @@ pub struct Ty<I: Interner> {
327328
interned: I::InternedType,
328329
}
329330

331+
///compute type flags for Lifetime
332+
fn compute_lifetime_flags<I: Interner>(lifetime: &Lifetime<I>, interner: &I) -> TypeFlags {
333+
match lifetime.data(&interner){
334+
LifetimeData::InferenceVar(_) => {
335+
TypeFlags::HAS_RE_INFER | TypeFlags::HAS_FREE_LOCAL_REGIONS | TypeFlags::HAS_FREE_REGIONS
336+
},
337+
LifetimeData::Placeholder(_) => {
338+
TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_FREE_LOCAL_REGIONS | TypeFlags::HAS_FREE_REGIONS
339+
},
340+
LifetimeData::Static
341+
| LifetimeData::Phantom(_,_)
342+
| LifetimeData::BoundVar(_) => {TypeFlags::empty()},
343+
}
344+
}
345+
346+
/// Compute type flags for Substitution<I>
347+
fn compute_substitution_flags<I: Interner> (substitution: &Substitution<I>, interner : &I) -> TypeFlags {
348+
let mut flags = TypeFlags::empty();
349+
for generic_arg in substitution.iter(&interner){
350+
flags |= compute_generic_arg_flags(generic_arg, &interner);
351+
}
352+
flags
353+
}
354+
355+
/// Compute type flags for GenericArg<I>
356+
fn compute_generic_arg_flags<I: Interner> (generic_arg: &GenericArg<I>, interner: &I) -> TypeFlags {
357+
match generic_arg.data(&interner) {
358+
GenericArgData::Ty(ty) => ty.data(interner).flags,
359+
GenericArgData::Lifetime(lifetime) => compute_lifetime_flags(lifetime, interner),
360+
GenericArgData::Const(constant) => {
361+
let data = constant.data(&interner);
362+
let flags = data.ty.data(interner).flags;
363+
match data.value {
364+
ConstValue::BoundVar(_) => flags,
365+
ConstValue::InferenceVar(_) => flags | TypeFlags::HAS_CT_INFER | TypeFlags::STILL_FURTHER_SPECIALIZABLE,
366+
ConstValue::Placeholder(_) => flags | TypeFlags::HAS_CT_PLACEHOLDER | TypeFlags::STILL_FURTHER_SPECIALIZABLE,
367+
ConstValue::Concrete(_) => flags,
368+
}
369+
}
370+
}
371+
}
372+
373+
/// Compute type flags for aliases
374+
fn compute_alias_flags<I: Interner>(alias_ty: &AliasTy<I>, interner: &I) -> TypeFlags {
375+
match alias_ty {
376+
AliasTy::Projection(projection_ty) => TypeFlags::HAS_TY_PROJECTION | compute_substitution_flags(&(projection_ty.substitution), interner),
377+
AliasTy::Opaque(opaque_ty) => TypeFlags::HAS_TY_OPAQUE | compute_substitution_flags(&(opaque_ty.substitution), interner)
378+
}
379+
}
380+
381+
/// Compute type flags for a TyKind
382+
fn compute_flags<I: Interner> (kind: &TyKind<I>, interner: &I) -> TypeFlags {
383+
match kind {
384+
TyKind::Adt(_, substitution)
385+
| TyKind::AssociatedType(_, substitution)
386+
| TyKind::Tuple(_, substitution)
387+
| TyKind::Closure(_, substitution)
388+
| TyKind::Generator(_, substitution)
389+
| TyKind::GeneratorWitness(_, substitution)
390+
| TyKind::FnDef(_, substitution) => compute_substitution_flags(substitution,interner),
391+
TyKind::Scalar(_)
392+
| TyKind::Str
393+
| TyKind::Never
394+
| TyKind::Foreign(_) => TypeFlags::empty(),
395+
TyKind::OpaqueType(_, substitution) => TypeFlags::HAS_TY_OPAQUE | compute_substitution_flags(substitution,interner),
396+
TyKind::Error => TypeFlags::HAS_ERROR,
397+
TyKind::Slice(ty)
398+
| TyKind::Raw(_, ty) => ty.data(interner).flags,
399+
TyKind::Ref(_, lifetime, ty) => compute_lifetime_flags(lifetime, interner) | ty.data(interner).flags,
400+
TyKind::Array(ty, const_ty) => {
401+
let flags = ty.data(interner).flags;
402+
let const_data = const_ty.data(interner);
403+
flags | const_data.ty.data(interner).flags | match const_data.value {
404+
ConstValue::BoundVar(_)
405+
| ConstValue::Concrete(_) => TypeFlags::empty(),
406+
ConstValue::InferenceVar(_) => TypeFlags::HAS_CT_INFER | TypeFlags::STILL_FURTHER_SPECIALIZABLE,
407+
ConstValue::Placeholder(_) => TypeFlags::HAS_CT_PLACEHOLDER | TypeFlags::STILL_FURTHER_SPECIALIZABLE
408+
}
409+
},
410+
TyKind::Placeholder(_) => TypeFlags::HAS_TY_PLACEHOLDER,
411+
TyKind::Dyn(dyn_ty) => {
412+
let lifetime_flags = compute_lifetime_flags(&(dyn_ty.lifetime),&interner);
413+
let mut dyn_flags = TypeFlags::empty();
414+
for var_kind in dyn_ty.bounds.value.iter(&interner) {
415+
match &(var_kind.value) {
416+
WhereClause::Implemented(trait_ref) => dyn_flags |= compute_substitution_flags(&(trait_ref.substitution), interner),
417+
WhereClause::AliasEq(alias_eq) => {
418+
dyn_flags |= compute_alias_flags(&(alias_eq.alias), &interner);
419+
dyn_flags |= alias_eq.ty.data(&interner).flags;
420+
},
421+
WhereClause::LifetimeOutlives(lifetime_outlives) => {
422+
dyn_flags |= compute_lifetime_flags( &(lifetime_outlives.a), &interner) | compute_lifetime_flags(&(lifetime_outlives.b), &interner);
423+
},
424+
WhereClause::TypeOutlives(type_outlives) => {
425+
dyn_flags |= type_outlives.ty.data(&interner).flags;
426+
dyn_flags |= compute_lifetime_flags(&(type_outlives.lifetime),&interner);
427+
}
428+
}
429+
};
430+
lifetime_flags | dyn_flags
431+
},
432+
TyKind::Alias(alias_ty) => compute_alias_flags(&alias_ty, &interner),
433+
TyKind::BoundVar(_) => TypeFlags::empty(),
434+
TyKind::InferenceVar(_,_) => TypeFlags::HAS_TY_INFER,
435+
TyKind::Function(fn_pointer) => compute_substitution_flags(&(fn_pointer.substitution), interner)
436+
}
437+
}
438+
330439
impl<I: Interner> Ty<I> {
331440
/// Creates a type from `TyKind`.
332441
pub fn new(interner: &I, data: impl CastTo<TyKind<I>>) -> Self {
442+
let ty_kind = data.cast(&interner);
333443
let data = TyData {
334-
kind: data.cast(interner),
444+
flags : compute_flags(&ty_kind, &interner),
445+
kind: ty_kind,
335446
};
336447
Ty {
337448
interned: I::intern_ty(interner, data),
@@ -446,8 +557,57 @@ impl<I: Interner> Ty<I> {
446557
pub struct TyData<I: Interner> {
447558
/// The kind
448559
pub kind: TyKind<I>,
560+
/// Type flags
561+
pub flags: TypeFlags,
562+
}
563+
564+
bitflags! {
565+
/// Contains flags indicating various properties of a Ty
566+
pub struct TypeFlags : u16 {
567+
/// Does the type contain an InferenceVar
568+
const HAS_TY_INFER = 1;
569+
/// Does the type contain a lifetime with an InferenceVar
570+
const HAS_RE_INFER = 1 << 1;
571+
/// Does the type contain a ConstValue with an InferenceVar
572+
const HAS_CT_INFER = 1 << 2;
573+
/// Does the type contain a Placeholder TyKind
574+
const HAS_TY_PLACEHOLDER = 1 << 3;
575+
/// Does the type contain a lifetime with a Placeholder
576+
const HAS_RE_PLACEHOLDER = 1 << 4;
577+
/// Does the type contain a ConstValue Placeholder
578+
const HAS_CT_PLACEHOLDER = 1 << 5;
579+
/// True when the type has free lifetimes related to a local context
580+
const HAS_FREE_LOCAL_REGIONS = 1 << 6;
581+
/// Does the type contain a projection of an associated type
582+
const HAS_TY_PROJECTION = 1 << 7;
583+
/// Does the type contain an opaque type
584+
const HAS_TY_OPAQUE = 1 << 8;
585+
/// Does the type contain an unevaluated const projection
586+
const HAS_CT_PROJECTION = 1 << 9;
587+
/// Does the type contain an error
588+
const HAS_ERROR = 1 << 10;
589+
/// Does the type contain any free lifetimes
590+
const HAS_FREE_REGIONS = 1 << 11;
591+
/// True when the type contains lifetimes that will be substituted when function is called
592+
const HAS_RE_LATE_BOUND = 1 << 12;
593+
/// True when the type contains an erased lifetime
594+
const HAS_RE_ERASED = 1 << 13;
595+
/// Does the type contain placeholders or inference variables that could be replaced later
596+
const STILL_FURTHER_SPECIALIZABLE = 1 << 14;
597+
598+
/// True when the type contains free names local to a particular context
599+
const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_INFER.bits
600+
| TypeFlags::HAS_CT_INFER.bits
601+
| TypeFlags::HAS_TY_PLACEHOLDER.bits
602+
| TypeFlags::HAS_CT_PLACEHOLDER.bits
603+
| TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
604+
605+
/// Does the type contain any form of projection
606+
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
607+
| TypeFlags::HAS_TY_OPAQUE.bits
608+
| TypeFlags::HAS_CT_PROJECTION.bits;
609+
}
449610
}
450-
451611
/// Type data, which holds the actual type information.
452612
#[derive(Clone, PartialEq, Eq, Hash, HasInterner)]
453613
pub enum TyKind<I: Interner> {

tests/test/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,4 @@ mod unify;
351351
mod unpin;
352352
mod unsize;
353353
mod wf_goals;
354+
mod type_flags;

tests/test/type_flags.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use chalk_integration::{ty, lifetime, empty_substitution};
2+
use chalk_ir::{TyKind, Ty, UniverseIndex, PlaceholderIndex};
3+
4+
#[test]
5+
fn placeholder_ty_flags_correct(){
6+
let placeholder_ty = ty!(placeholder 0);
7+
assert_eq!(placeholder_ty.data(&chalk_integration::interner::ChalkIr).flags, chalk_ir::TypeFlags::HAS_TY_PLACEHOLDER);
8+
}
9+
10+
#[test]
11+
fn opaque_ty_flags_correct(){
12+
let x : Vec<chalk_ir::GenericArg<chalk_integration::interner::ChalkIr>> = vec!(
13+
chalk_ir::GenericArg::new(&chalk_integration::interner::ChalkIr, chalk_ir::GenericArgData::Const(
14+
chalk_ir::Const::new(&chalk_integration::interner::ChalkIr, chalk_ir::ConstData{
15+
ty : Ty::new(&chalk_integration::interner::ChalkIr,
16+
TyKind::Placeholder(PlaceholderIndex{
17+
ui : chalk_ir::UniverseIndex::ROOT,
18+
idx : 0
19+
})),
20+
value : chalk_ir::ConstValue::InferenceVar(chalk_ir::InferenceVar::from(0))
21+
})
22+
))
23+
);
24+
let opaque_ty_kind = TyKind::OpaqueType(chalk_ir::OpaqueTyId{0 : chalk_integration::interner::RawId{ index : 0 }},
25+
chalk_ir::Substitution::from_iter(&chalk_integration::interner::ChalkIr, x));
26+
let opaque_ty = Ty::new(&chalk_integration::interner::ChalkIr, opaque_ty_kind);
27+
assert_eq!(opaque_ty.data(&chalk_integration::interner::ChalkIr).flags,
28+
chalk_ir::TypeFlags::HAS_TY_OPAQUE | chalk_ir::TypeFlags::HAS_CT_INFER | chalk_ir::TypeFlags::STILL_FURTHER_SPECIALIZABLE
29+
| chalk_ir::TypeFlags::HAS_TY_PLACEHOLDER);
30+
}
31+
32+
#[test]
33+
fn dyn_ty_flags_correct(){
34+
let internal_ty = Ty::new(&chalk_integration::interner::ChalkIr,
35+
chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Bool));
36+
let projection_ty = chalk_ir::ProjectionTy{
37+
associated_ty_id : chalk_ir::AssocTypeId{
38+
0 : chalk_integration::interner::RawId{ index : 0 }
39+
},
40+
substitution: empty_substitution!()
41+
};
42+
let bounds = chalk_ir::Binders::<chalk_ir::QuantifiedWhereClauses<chalk_integration::interner::ChalkIr>>::empty(
43+
&chalk_integration::interner::ChalkIr,
44+
chalk_ir::QuantifiedWhereClauses::from_iter(&chalk_integration::interner::ChalkIr,
45+
vec!(chalk_ir::Binders::<chalk_ir::WhereClause<chalk_integration::interner::ChalkIr>>::empty(
46+
&chalk_integration::interner::ChalkIr,
47+
chalk_ir::WhereClause::AliasEq(
48+
chalk_ir::AliasEq{
49+
ty : internal_ty,
50+
alias : chalk_ir::AliasTy::Projection(projection_ty)
51+
}
52+
)
53+
)))
54+
);
55+
let dyn_ty = chalk_ir::DynTy {
56+
lifetime : lifetime!(placeholder 5),
57+
bounds : bounds
58+
};
59+
let ty = chalk_ir::Ty::new(&chalk_integration::interner::ChalkIr, TyKind::Dyn(dyn_ty));
60+
assert_eq!(ty.data(&chalk_integration::interner::ChalkIr).flags,
61+
chalk_ir::TypeFlags::HAS_TY_PROJECTION | chalk_ir::TypeFlags::HAS_RE_PLACEHOLDER |
62+
chalk_ir::TypeFlags::HAS_FREE_LOCAL_REGIONS | chalk_ir::TypeFlags::HAS_FREE_REGIONS);
63+
}
64+
65+
#[test]
66+
fn flagless_ty_has_no_flags(){
67+
let ty = Ty::new(&chalk_integration::interner::ChalkIr, TyKind::Str);
68+
assert_eq!(ty.data(&chalk_integration::interner::ChalkIr).flags, chalk_ir::TypeFlags::empty());
69+
70+
let fn_ty = Ty::new(&chalk_integration::interner::ChalkIr, TyKind::Function(
71+
chalk_ir::FnPointer{
72+
num_binders : 0,
73+
substitution : empty_substitution!(),
74+
sig : chalk_ir::FnSig{
75+
abi: chalk_integration::interner::ChalkFnAbi::Rust,
76+
safety : chalk_ir::Safety::Safe,
77+
variadic : false
78+
}
79+
}
80+
));
81+
assert_eq!(fn_ty.data(&chalk_integration::interner::ChalkIr).flags, chalk_ir::TypeFlags::empty());
82+
}
83+
84+
#[test]
85+
fn flagless_lifetime_contributes_no_flags(){
86+
let substitutions = chalk_ir::Substitution::from_iter(&chalk_integration::interner::ChalkIr,
87+
vec!(
88+
chalk_ir::GenericArg::new(&chalk_integration::interner::ChalkIr
89+
,chalk_ir::GenericArgData::Lifetime(chalk_ir::Lifetime::new(&chalk_integration::interner::ChalkIr, chalk_ir::LifetimeData::Static))),
90+
chalk_ir::GenericArg::new(&chalk_integration::interner::ChalkIr
91+
,chalk_ir::GenericArgData::Lifetime(lifetime!(bound 5)))
92+
));
93+
94+
let ty = Ty::new(&chalk_integration::interner::ChalkIr, TyKind::Adt(
95+
chalk_ir::AdtId{
96+
0 : chalk_integration::interner::RawId{ index : 0 }
97+
}
98+
,substitutions
99+
));
100+
101+
assert_eq!(ty.data(&chalk_integration::interner::ChalkIr).flags, chalk_ir::TypeFlags::empty());
102+
}

0 commit comments

Comments
 (0)