Skip to content

Commit d362b5e

Browse files
committed
Generate auto trait clauses for opaque type goals
1 parent 5e5e4b1 commit d362b5e

File tree

4 files changed

+110
-3
lines changed

4 files changed

+110
-3
lines changed

chalk-ir/src/cast.rs

+9
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,15 @@ where
319319
}
320320
}
321321

322+
impl<I> CastTo<TypeName<I>> for OpaqueTyId<I>
323+
where
324+
I: Interner,
325+
{
326+
fn cast_to(self, _interner: &I) -> TypeName<I> {
327+
TypeName::OpaqueType(self)
328+
}
329+
}
330+
322331
impl<T> CastTo<T> for &T
323332
where
324333
T: Clone + HasInterner,

chalk-solve/src/clauses.rs

+67-1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,69 @@ pub fn push_auto_trait_impls<I: Interner>(
104104
});
105105
}
106106

107+
/// Leak auto traits for opaque types, just like `push_auto_trait_impls` does for structs.
108+
///
109+
/// For example, given the following program:
110+
///
111+
/// ```notrust
112+
/// #[auto] trait Send { }
113+
/// trait Trait { }
114+
/// struct Bar { }
115+
/// opaque type Foo: Trait = Bar
116+
/// ```
117+
/// Checking the goal `Foo: Send` would generate the following:
118+
///
119+
/// ```notrust
120+
/// Foo: Send :- Bar: Send
121+
/// ```
122+
pub fn push_auto_trait_impls_opaque<I: Interner>(
123+
builder: &mut ClauseBuilder<'_, I>,
124+
auto_trait_id: TraitId<I>,
125+
opaque_id: OpaqueTyId<I>,
126+
) {
127+
debug_heading!(
128+
"push_auto_trait_impls_opaque({:?}, {:?})",
129+
auto_trait_id,
130+
opaque_id
131+
);
132+
133+
let opaque_ty_datum = &builder.db.opaque_ty_data(opaque_id);
134+
let interner = builder.interner();
135+
136+
// Must be an auto trait.
137+
assert!(builder.db.trait_datum(auto_trait_id).is_auto_trait());
138+
139+
// Auto traits never have generic parameters of their own (apart from `Self`).
140+
assert_eq!(
141+
builder.db.trait_datum(auto_trait_id).binders.len(interner),
142+
1
143+
);
144+
145+
let binders = opaque_ty_datum.bound.map_ref(|b| &b.hidden_ty);
146+
builder.push_binders(&binders, |builder, hidden_ty| {
147+
let self_ty: Ty<_> = ApplicationTy {
148+
name: opaque_id.cast(interner),
149+
substitution: builder.substitution_in_scope(),
150+
}
151+
.intern(interner);
152+
153+
// trait_ref = `OpaqueType<...>: MyAutoTrait`
154+
let auto_trait_ref = TraitRef {
155+
trait_id: auto_trait_id,
156+
substitution: Substitution::from1(interner, self_ty),
157+
};
158+
159+
// OpaqueType<...>: MyAutoTrait :- HiddenType: MyAutoTrait
160+
builder.push_clause(
161+
auto_trait_ref,
162+
std::iter::once(TraitRef {
163+
trait_id: auto_trait_id,
164+
substitution: Substitution::from1(interner, hidden_ty.clone()),
165+
}),
166+
);
167+
});
168+
}
169+
107170
/// Given some goal `goal` that must be proven, along with
108171
/// its `environment`, figures out the program clauses that apply
109172
/// to this goal from the Rust program. So for example if the goal
@@ -161,7 +224,10 @@ fn program_clauses_that_could_match<I: Interner>(
161224

162225
if trait_datum.is_non_enumerable_trait() || trait_datum.is_auto_trait() {
163226
let self_ty = trait_ref.self_type_parameter(interner);
164-
if self_ty.bound_var(interner).is_some()
227+
228+
if let TyData::Alias(AliasTy::Opaque(opaque_ty)) = self_ty.data(interner) {
229+
push_auto_trait_impls_opaque(builder, trait_id, opaque_ty.opaque_ty_id)
230+
} else if self_ty.bound_var(interner).is_some()
165231
|| self_ty.inference_var(interner).is_some()
166232
{
167233
return Err(Floundered);

chalk-solve/src/clauses/program_clauses.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ impl<I: Interner> ToProgramClauses<I> for OpaqueTyDatum<I> {
126126
/// AliasEq(T<..> = !T<..>).
127127
/// Implemented(!T<..>: A).
128128
/// Implemented(!T<..>: B).
129-
/// Implemented(!T<..>: Send) :- Implemented(HiddenTy: Send). // For all auto traits
130129
/// ```
131130
/// where `!T<..>` is the placeholder for the unnormalized type `T<..>`.
132131
fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) {
@@ -142,7 +141,7 @@ impl<I: Interner> ToProgramClauses<I> for OpaqueTyDatum<I> {
142141
let alias_placeholder_ty = Ty::new(
143142
interner,
144143
ApplicationTy {
145-
name: TypeName::OpaqueType(self.opaque_ty_id),
144+
name: self.opaque_ty_id.cast(interner),
146145
substitution,
147146
},
148147
);

tests/test/opaque_types.rs

+33
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,36 @@ fn opaque_generics() {
9898

9999
}
100100
}
101+
102+
#[test]
103+
fn opaque_auto_traits() {
104+
test! {
105+
program {
106+
struct Bar { }
107+
struct Baz { }
108+
trait Trait { }
109+
110+
#[auto]
111+
trait Send { }
112+
113+
impl !Send for Baz { }
114+
115+
opaque type Opaque1: Trait = Bar;
116+
opaque type Opaque2: Trait = Baz;
117+
}
118+
119+
goal {
120+
Opaque1: Send
121+
} yields {
122+
"Unique"
123+
}
124+
125+
goal {
126+
if (Reveal) {
127+
Opaque2: Send
128+
}
129+
} yields {
130+
"No possible solution"
131+
}
132+
}
133+
}

0 commit comments

Comments
 (0)