Skip to content

Commit 37a38f9

Browse files
authored
Merge pull request #445 from Mcat12/feature/object-safe
Add ObjectSafe goal and flag
2 parents 26fe3f9 + 939926a commit 37a38f9

File tree

12 files changed

+66
-16
lines changed

12 files changed

+66
-16
lines changed

chalk-integration/src/db.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,8 @@ impl RustIrDatabase<ChalkIr> for ChalkDatabase {
156156
fn interner(&self) -> &ChalkIr {
157157
&ChalkIr
158158
}
159+
160+
fn is_object_safe(&self, trait_id: TraitId<ChalkIr>) -> bool {
161+
self.program_ir().unwrap().is_object_safe(trait_id)
162+
}
159163
}

chalk-integration/src/lowering.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use chalk_rust_ir as rust_ir;
1010
use chalk_rust_ir::{
1111
Anonymize, AssociatedTyValueId, IntoWhereClauses, OpaqueTyDatum, OpaqueTyDatumBound,
1212
};
13-
use std::collections::BTreeMap;
13+
use std::collections::{BTreeMap, HashSet};
1414
use std::sync::Arc;
1515
use string_cache::DefaultAtom as Atom;
1616

@@ -243,6 +243,7 @@ impl LowerProgram for Program {
243243
let mut struct_kinds = BTreeMap::new();
244244
let mut trait_kinds = BTreeMap::new();
245245
let mut opaque_ty_kinds = BTreeMap::new();
246+
let mut object_safe_traits = HashSet::new();
246247
for (item, &raw_id) in self.items.iter().zip(&raw_ids) {
247248
match item {
248249
Item::StructDefn(defn) => {
@@ -256,6 +257,10 @@ impl LowerProgram for Program {
256257
let id = TraitId(raw_id);
257258
trait_ids.insert(type_kind.name.clone(), id);
258259
trait_kinds.insert(id, type_kind);
260+
261+
if defn.flags.object_safe {
262+
object_safe_traits.insert(id);
263+
}
259264
}
260265
Item::OpaqueTyDefn(defn) => {
261266
let type_kind = defn.lower_type_kind()?;
@@ -457,6 +462,7 @@ impl LowerProgram for Program {
457462
opaque_ty_kinds,
458463
opaque_ty_data,
459464
custom_clauses,
465+
object_safe_traits,
460466
};
461467

462468
Ok(program)
@@ -758,6 +764,9 @@ impl LowerDomainGoal for DomainGoal {
758764
vec![chalk_ir::DomainGoal::DownstreamType(ty.lower(env)?)]
759765
}
760766
DomainGoal::Reveal => vec![chalk_ir::DomainGoal::Reveal(())],
767+
DomainGoal::ObjectSafe { id } => {
768+
vec![chalk_ir::DomainGoal::ObjectSafe(env.lookup_trait(id)?)]
769+
}
761770
};
762771
Ok(goals)
763772
}

chalk-integration/src/program.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use chalk_rust_ir::{
1313
};
1414
use chalk_solve::split::Split;
1515
use chalk_solve::RustIrDatabase;
16-
use std::collections::BTreeMap;
16+
use std::collections::{BTreeMap, HashSet};
1717
use std::fmt;
1818
use std::sync::Arc;
1919

@@ -61,6 +61,9 @@ pub struct Program {
6161

6262
/// For each user-specified clause
6363
pub custom_clauses: Vec<ProgramClause<ChalkIr>>,
64+
65+
/// Store the traits marked with `#[object_safe]`
66+
pub object_safe_traits: HashSet<TraitId<ChalkIr>>,
6467
}
6568

6669
impl Program {
@@ -392,4 +395,8 @@ impl RustIrDatabase<ChalkIr> for Program {
392395
fn interner(&self) -> &ChalkIr {
393396
&ChalkIr
394397
}
398+
399+
fn is_object_safe(&self, trait_id: TraitId<ChalkIr>) -> bool {
400+
self.object_safe_traits.contains(&trait_id)
401+
}
395402
}

chalk-ir/src/debug.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ impl<I: Interner> Debug for DomainGoal<I> {
629629
DomainGoal::Compatible(_) => write!(fmt, "Compatible"),
630630
DomainGoal::DownstreamType(n) => write!(fmt, "DownstreamType({:?})", n),
631631
DomainGoal::Reveal(_) => write!(fmt, "Reveal"),
632+
DomainGoal::ObjectSafe(n) => write!(fmt, "ObjectSafe({:?})", n),
632633
}
633634
}
634635
}

chalk-ir/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,9 @@ pub enum DomainGoal<I: Interner> {
10911091
/// Used to activate the "reveal mode", in which opaque (`impl Trait`) types can be equated
10921092
/// to their actual type.
10931093
Reveal(()),
1094+
1095+
/// Used to indicate that a trait is object safe.
1096+
ObjectSafe(TraitId<I>),
10941097
}
10951098

10961099
pub type QuantifiedWhereClause<I> = Binders<WhereClause<I>>;

chalk-parse/src/ast.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub struct TraitFlags {
6868
pub fundamental: bool,
6969
pub non_enumerable: bool,
7070
pub coinductive: bool,
71+
pub object_safe: bool,
7172
}
7273

7374
#[derive(Clone, PartialEq, Eq, Debug)]
@@ -318,6 +319,7 @@ pub enum DomainGoal {
318319
Compatible,
319320
DownstreamType { ty: Ty },
320321
Reveal,
322+
ObjectSafe { id: Identifier },
321323
}
322324

323325
#[derive(Clone, PartialEq, Eq, Debug)]

chalk-parse/src/parser.lalrpop

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ MarkerKeyword: () = "#" "[" "marker" "]";
4343
FundamentalKeyword: () = "#" "[" "fundamental" "]";
4444
NonEnumerableKeyword: () = "#" "[" "non_enumerable" "]";
4545
CoinductiveKeyword: () = "#" "[" "coinductive" "]";
46+
ObjectSafeKeyword: () = "#" "[" "object_safe" "]";
4647

4748
WellKnownTrait: WellKnownTrait = {
4849
"#" "[" "lang" "(" "sized" ")" "]" => WellKnownTrait::SizedTrait,
@@ -67,7 +68,7 @@ StructDefn: StructDefn = {
6768
};
6869

6970
TraitDefn: TraitDefn = {
70-
<auto:AutoKeyword?> <marker:MarkerKeyword?> <upstream:UpstreamKeyword?> <fundamental:FundamentalKeyword?> <non_enumerable:NonEnumerableKeyword?> <coinductive:CoinductiveKeyword?> <well_known:WellKnownTrait?> "trait" <n:Id><p:Angle<ParameterKind>>
71+
<auto:AutoKeyword?> <marker:MarkerKeyword?> <upstream:UpstreamKeyword?> <fundamental:FundamentalKeyword?> <non_enumerable:NonEnumerableKeyword?> <coinductive:CoinductiveKeyword?> <object_safe:ObjectSafeKeyword?> <well_known:WellKnownTrait?> "trait" <n:Id><p:Angle<ParameterKind>>
7172
<w:QuantifiedWhereClauses> "{" <a:AssocTyDefn*> "}" => TraitDefn
7273
{
7374
name: n,
@@ -82,6 +83,7 @@ TraitDefn: TraitDefn = {
8283
fundamental: fundamental.is_some(),
8384
non_enumerable: non_enumerable.is_some(),
8485
coinductive: coinductive.is_some(),
86+
object_safe: object_safe.is_some(),
8587
},
8688
}
8789
};
@@ -366,6 +368,8 @@ DomainGoal: DomainGoal = {
366368
"DownstreamType" "(" <ty:Ty> ")" => DomainGoal::DownstreamType { ty },
367369

368370
"Reveal" => DomainGoal::Reveal,
371+
372+
"ObjectSafe" "(" <id:Id> ")" => DomainGoal::ObjectSafe { id }
369373
};
370374

371375
LeafGoal: LeafGoal = {

chalk-solve/src/clauses.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -244,16 +244,21 @@ fn program_clauses_that_could_match<I: Interner>(
244244
.opaque_ty_data(opaque_ty.opaque_ty_id)
245245
.to_program_clauses(builder),
246246
},
247-
DomainGoal::WellFormed(WellFormed::Trait(trait_predicate)) => {
248-
db.trait_datum(trait_predicate.trait_id)
247+
DomainGoal::WellFormed(WellFormed::Trait(trait_ref))
248+
| DomainGoal::LocalImplAllowed(trait_ref) => {
249+
db.trait_datum(trait_ref.trait_id)
249250
.to_program_clauses(builder);
250251
}
252+
DomainGoal::ObjectSafe(trait_id) => {
253+
if builder.db.is_object_safe(*trait_id) {
254+
builder.push_fact(DomainGoal::ObjectSafe(*trait_id));
255+
}
256+
}
251257
DomainGoal::WellFormed(WellFormed::Ty(ty))
252258
| DomainGoal::IsUpstream(ty)
253-
| DomainGoal::DownstreamType(ty) => match_ty(builder, environment, ty)?,
254-
DomainGoal::IsFullyVisible(ty) | DomainGoal::IsLocal(ty) => {
255-
match_ty(builder, environment, ty)?
256-
}
259+
| DomainGoal::DownstreamType(ty)
260+
| DomainGoal::IsFullyVisible(ty)
261+
| DomainGoal::IsLocal(ty) => match_ty(builder, environment, ty)?,
257262
DomainGoal::FromEnv(_) => (), // Computed in the environment
258263
DomainGoal::Normalize(Normalize { alias, ty: _ }) => match alias {
259264
AliasTy::Projection(proj) => {
@@ -291,11 +296,7 @@ fn program_clauses_that_could_match<I: Interner>(
291296
}
292297
AliasTy::Opaque(_) => (),
293298
},
294-
DomainGoal::LocalImplAllowed(trait_ref) => db
295-
.trait_datum(trait_ref.trait_id)
296-
.to_program_clauses(builder),
297-
DomainGoal::Compatible(()) => (),
298-
DomainGoal::Reveal(()) => (),
299+
DomainGoal::Compatible(()) | DomainGoal::Reveal(()) => (),
299300
};
300301

301302
Ok(())

chalk-solve/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ pub trait RustIrDatabase<I: Interner>: Debug {
9393
fn program_clauses_for_env(&self, environment: &Environment<I>) -> ProgramClauses<I>;
9494

9595
fn interner(&self) -> &I;
96+
97+
/// Check if a trait is object safe
98+
fn is_object_safe(&self, trait_id: TraitId<I>) -> bool;
9699
}
97100

98101
pub use clauses::program_clauses_for_env;

tests/lowering/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ fn scalars() {
471471
}
472472

473473
error_msg {
474-
"parse error: UnrecognizedToken { token: (8, Token(52, \"i32\"), 11), expected: [\"r#\\\"([A-Za-z]|_)([A-Za-z0-9]|_)*\\\"#\"] }"
474+
"parse error: UnrecognizedToken { token: (8, Token(53, \"i32\"), 11), expected: [\"r#\\\"([A-Za-z]|_)([A-Za-z0-9]|_)*\\\"#\"] }"
475475
}
476476
}
477477
}
@@ -505,7 +505,7 @@ fn raw_pointers() {
505505
impl Foo for *i32 { }
506506
}
507507
error_msg {
508-
"parse error: UnrecognizedToken { token: (30, Token(52, \"i32\"), 33), expected: [\"\\\"const\\\"\", \"\\\"mut\\\"\"] }"
508+
"parse error: UnrecognizedToken { token: (30, Token(53, \"i32\"), 33), expected: [\"\\\"const\\\"\", \"\\\"mut\\\"\"] }"
509509
}
510510
}
511511
}

0 commit comments

Comments
 (0)