Skip to content

Commit a3a3e1e

Browse files
committed
Auto merge of #639 - chfont:add-type-flags, r=matthewjasper
Add TypeFlags for TyKind in chalk-ir Closes #627
2 parents 148e6a7 + a8b61ff commit a3a3e1e

File tree

6 files changed

+323
-3
lines changed

6 files changed

+323
-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: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,10 @@ macro_rules! lifetime {
119119
lifetime!($($b)*)
120120
};
121121
}
122+
123+
#[macro_export]
124+
macro_rules! empty_substitution {
125+
() => {
126+
chalk_ir::Substitution::empty(&chalk_integration::interner::ChalkIr)
127+
};
128+
}

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.44.0-dev.0", path = "../chalk-derive" }

chalk-ir/src/lib.rs

Lines changed: 189 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 {}
@@ -411,11 +412,147 @@ pub struct Ty<I: Interner> {
411412
interned: I::InternedType,
412413
}
413414

415+
///compute type flags for Lifetime
416+
fn compute_lifetime_flags<I: Interner>(lifetime: &Lifetime<I>, interner: &I) -> TypeFlags {
417+
match lifetime.data(&interner) {
418+
LifetimeData::InferenceVar(_) => {
419+
TypeFlags::HAS_RE_INFER
420+
| TypeFlags::HAS_FREE_LOCAL_REGIONS
421+
| TypeFlags::HAS_FREE_REGIONS
422+
}
423+
LifetimeData::Placeholder(_) => {
424+
TypeFlags::HAS_RE_PLACEHOLDER
425+
| TypeFlags::HAS_FREE_LOCAL_REGIONS
426+
| TypeFlags::HAS_FREE_REGIONS
427+
}
428+
LifetimeData::Static | LifetimeData::Empty(_) => TypeFlags::HAS_FREE_REGIONS,
429+
LifetimeData::Phantom(_, _) => TypeFlags::empty(),
430+
LifetimeData::BoundVar(_) => TypeFlags::HAS_RE_LATE_BOUND,
431+
LifetimeData::Erased => TypeFlags::HAS_RE_ERASED,
432+
}
433+
}
434+
435+
/// Compute type flags for Substitution<I>
436+
fn compute_substitution_flags<I: Interner>(
437+
substitution: &Substitution<I>,
438+
interner: &I,
439+
) -> TypeFlags {
440+
let mut flags = TypeFlags::empty();
441+
for generic_arg in substitution.iter(&interner) {
442+
flags |= compute_generic_arg_flags(generic_arg, &interner);
443+
}
444+
flags
445+
}
446+
447+
/// Compute type flags for GenericArg<I>
448+
fn compute_generic_arg_flags<I: Interner>(generic_arg: &GenericArg<I>, interner: &I) -> TypeFlags {
449+
match generic_arg.data(&interner) {
450+
GenericArgData::Ty(ty) => ty.data(interner).flags,
451+
GenericArgData::Lifetime(lifetime) => compute_lifetime_flags(lifetime, interner),
452+
GenericArgData::Const(constant) => {
453+
let data = constant.data(&interner);
454+
let flags = data.ty.data(interner).flags;
455+
match data.value {
456+
ConstValue::BoundVar(_) => flags,
457+
ConstValue::InferenceVar(_) => {
458+
flags | TypeFlags::HAS_CT_INFER | TypeFlags::STILL_FURTHER_SPECIALIZABLE
459+
}
460+
ConstValue::Placeholder(_) => {
461+
flags | TypeFlags::HAS_CT_PLACEHOLDER | TypeFlags::STILL_FURTHER_SPECIALIZABLE
462+
}
463+
ConstValue::Concrete(_) => flags,
464+
}
465+
}
466+
}
467+
}
468+
469+
/// Compute type flags for aliases
470+
fn compute_alias_flags<I: Interner>(alias_ty: &AliasTy<I>, interner: &I) -> TypeFlags {
471+
match alias_ty {
472+
AliasTy::Projection(projection_ty) => {
473+
TypeFlags::HAS_TY_PROJECTION
474+
| compute_substitution_flags(&(projection_ty.substitution), interner)
475+
}
476+
AliasTy::Opaque(opaque_ty) => {
477+
TypeFlags::HAS_TY_OPAQUE
478+
| compute_substitution_flags(&(opaque_ty.substitution), interner)
479+
}
480+
}
481+
}
482+
483+
/// Compute type flags for a TyKind
484+
fn compute_flags<I: Interner>(kind: &TyKind<I>, interner: &I) -> TypeFlags {
485+
match kind {
486+
TyKind::Adt(_, substitution)
487+
| TyKind::AssociatedType(_, substitution)
488+
| TyKind::Tuple(_, substitution)
489+
| TyKind::Closure(_, substitution)
490+
| TyKind::Generator(_, substitution)
491+
| TyKind::GeneratorWitness(_, substitution)
492+
| TyKind::FnDef(_, substitution)
493+
| TyKind::OpaqueType(_, substitution) => compute_substitution_flags(substitution, interner),
494+
TyKind::Scalar(_) | TyKind::Str | TyKind::Never | TyKind::Foreign(_) => TypeFlags::empty(),
495+
TyKind::Error => TypeFlags::HAS_ERROR,
496+
TyKind::Slice(ty) | TyKind::Raw(_, ty) => ty.data(interner).flags,
497+
TyKind::Ref(_, lifetime, ty) => {
498+
compute_lifetime_flags(lifetime, interner) | ty.data(interner).flags
499+
}
500+
TyKind::Array(ty, const_ty) => {
501+
let flags = ty.data(interner).flags;
502+
let const_data = const_ty.data(interner);
503+
flags
504+
| const_data.ty.data(interner).flags
505+
| match const_data.value {
506+
ConstValue::BoundVar(_) | ConstValue::Concrete(_) => TypeFlags::empty(),
507+
ConstValue::InferenceVar(_) => {
508+
TypeFlags::HAS_CT_INFER | TypeFlags::STILL_FURTHER_SPECIALIZABLE
509+
}
510+
ConstValue::Placeholder(_) => {
511+
TypeFlags::HAS_CT_PLACEHOLDER | TypeFlags::STILL_FURTHER_SPECIALIZABLE
512+
}
513+
}
514+
}
515+
TyKind::Placeholder(_) => TypeFlags::HAS_TY_PLACEHOLDER,
516+
TyKind::Dyn(dyn_ty) => {
517+
let lifetime_flags = compute_lifetime_flags(&(dyn_ty.lifetime), &interner);
518+
let mut dyn_flags = TypeFlags::empty();
519+
for var_kind in dyn_ty.bounds.value.iter(&interner) {
520+
match &(var_kind.value) {
521+
WhereClause::Implemented(trait_ref) => {
522+
dyn_flags |= compute_substitution_flags(&(trait_ref.substitution), interner)
523+
}
524+
WhereClause::AliasEq(alias_eq) => {
525+
dyn_flags |= compute_alias_flags(&(alias_eq.alias), &interner);
526+
dyn_flags |= alias_eq.ty.data(&interner).flags;
527+
}
528+
WhereClause::LifetimeOutlives(lifetime_outlives) => {
529+
dyn_flags |= compute_lifetime_flags(&(lifetime_outlives.a), &interner)
530+
| compute_lifetime_flags(&(lifetime_outlives.b), &interner);
531+
}
532+
WhereClause::TypeOutlives(type_outlives) => {
533+
dyn_flags |= type_outlives.ty.data(&interner).flags;
534+
dyn_flags |= compute_lifetime_flags(&(type_outlives.lifetime), &interner);
535+
}
536+
}
537+
}
538+
lifetime_flags | dyn_flags
539+
}
540+
TyKind::Alias(alias_ty) => compute_alias_flags(&alias_ty, &interner),
541+
TyKind::BoundVar(_) => TypeFlags::empty(),
542+
TyKind::InferenceVar(_, _) => TypeFlags::HAS_TY_INFER,
543+
TyKind::Function(fn_pointer) => {
544+
compute_substitution_flags(&fn_pointer.substitution.0, interner)
545+
}
546+
}
547+
}
548+
414549
impl<I: Interner> Ty<I> {
415550
/// Creates a type from `TyKind`.
416551
pub fn new(interner: &I, data: impl CastTo<TyKind<I>>) -> Self {
552+
let ty_kind = data.cast(&interner);
417553
let data = TyData {
418-
kind: data.cast(interner),
554+
flags: compute_flags(&ty_kind, &interner),
555+
kind: ty_kind,
419556
};
420557
Ty {
421558
interned: I::intern_ty(interner, data),
@@ -530,8 +667,57 @@ impl<I: Interner> Ty<I> {
530667
pub struct TyData<I: Interner> {
531668
/// The kind
532669
pub kind: TyKind<I>,
670+
/// Type flags
671+
pub flags: TypeFlags,
672+
}
673+
674+
bitflags! {
675+
/// Contains flags indicating various properties of a Ty
676+
pub struct TypeFlags : u16 {
677+
/// Does the type contain an InferenceVar
678+
const HAS_TY_INFER = 1;
679+
/// Does the type contain a lifetime with an InferenceVar
680+
const HAS_RE_INFER = 1 << 1;
681+
/// Does the type contain a ConstValue with an InferenceVar
682+
const HAS_CT_INFER = 1 << 2;
683+
/// Does the type contain a Placeholder TyKind
684+
const HAS_TY_PLACEHOLDER = 1 << 3;
685+
/// Does the type contain a lifetime with a Placeholder
686+
const HAS_RE_PLACEHOLDER = 1 << 4;
687+
/// Does the type contain a ConstValue Placeholder
688+
const HAS_CT_PLACEHOLDER = 1 << 5;
689+
/// True when the type has free lifetimes related to a local context
690+
const HAS_FREE_LOCAL_REGIONS = 1 << 6;
691+
/// Does the type contain a projection of an associated type
692+
const HAS_TY_PROJECTION = 1 << 7;
693+
/// Does the type contain an opaque type
694+
const HAS_TY_OPAQUE = 1 << 8;
695+
/// Does the type contain an unevaluated const projection
696+
const HAS_CT_PROJECTION = 1 << 9;
697+
/// Does the type contain an error
698+
const HAS_ERROR = 1 << 10;
699+
/// Does the type contain any free lifetimes
700+
const HAS_FREE_REGIONS = 1 << 11;
701+
/// True when the type contains lifetimes that will be substituted when function is called
702+
const HAS_RE_LATE_BOUND = 1 << 12;
703+
/// True when the type contains an erased lifetime
704+
const HAS_RE_ERASED = 1 << 13;
705+
/// Does the type contain placeholders or inference variables that could be replaced later
706+
const STILL_FURTHER_SPECIALIZABLE = 1 << 14;
707+
708+
/// True when the type contains free names local to a particular context
709+
const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_INFER.bits
710+
| TypeFlags::HAS_CT_INFER.bits
711+
| TypeFlags::HAS_TY_PLACEHOLDER.bits
712+
| TypeFlags::HAS_CT_PLACEHOLDER.bits
713+
| TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
714+
715+
/// Does the type contain any form of projection
716+
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
717+
| TypeFlags::HAS_TY_OPAQUE.bits
718+
| TypeFlags::HAS_CT_PROJECTION.bits;
719+
}
533720
}
534-
535721
/// Type data, which holds the actual type information.
536722
#[derive(Clone, PartialEq, Eq, Hash, HasInterner)]
537723
pub enum TyKind<I: Interner> {

tests/test/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ mod slices;
349349
mod string;
350350
mod subtype;
351351
mod tuples;
352+
mod type_flags;
352353
mod unify;
353354
mod unpin;
354355
mod unsize;

tests/test/type_flags.rs

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

0 commit comments

Comments
 (0)