Skip to content

Commit 389a261

Browse files
committed
Auto merge of #638 - matthewjasper:clauses-cleanup, r=jackh726
Clauses cleanup - Add basic clauses for trait objects being wf - Push clauses for auto traits on `TyKind::OpaqueType` - Use a single match on the `TyKind` for Implemented goals - Normalize `TyKind::Alias` self types
2 parents 944fce6 + 575b0ec commit 389a261

File tree

4 files changed

+305
-66
lines changed

4 files changed

+305
-66
lines changed

chalk-ir/src/lib.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,12 +1468,7 @@ impl<I: Interner> AliasTy<I> {
14681468
/// Gets the type parameters of the `Self` type in this alias type.
14691469
pub fn self_type_parameter(&self, interner: &I) -> Ty<I> {
14701470
match self {
1471-
AliasTy::Projection(projection_ty) => projection_ty
1472-
.substitution
1473-
.iter(interner)
1474-
.find_map(move |p| p.ty(interner))
1475-
.unwrap()
1476-
.clone(),
1471+
AliasTy::Projection(projection_ty) => projection_ty.self_type_parameter(interner),
14771472
_ => todo!(),
14781473
}
14791474
}
@@ -1490,6 +1485,17 @@ pub struct ProjectionTy<I: Interner> {
14901485

14911486
impl<I: Interner> Copy for ProjectionTy<I> where I::InternedSubstitution: Copy {}
14921487

1488+
impl<I: Interner> ProjectionTy<I> {
1489+
/// Gets the type parameters of the `Self` type in this alias type.
1490+
pub fn self_type_parameter(&self, interner: &I) -> Ty<I> {
1491+
self.substitution
1492+
.iter(interner)
1493+
.find_map(move |p| p.ty(interner))
1494+
.unwrap()
1495+
.clone()
1496+
}
1497+
}
1498+
14931499
/// An opaque type `opaque type T<..>: Trait = HiddenTy`.
14941500
#[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner)]
14951501
pub struct OpaqueTy<I: Interner> {

chalk-solve/src/clauses.rs

Lines changed: 192 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@ fn constituent_types<I: Interner>(db: &dyn RustIrDatabase<I>, ty: &TyKind<I>) ->
7575
TyKind::Alias(_) => panic!("this function should not be called for alias"),
7676
TyKind::Foreign(_) => panic!("constituent_types of foreign types are unknown!"),
7777
TyKind::Error => Vec::new(),
78-
TyKind::OpaqueType(_, _) => unimplemented!(),
79-
TyKind::AssociatedType(_, _) => unimplemented!(),
78+
TyKind::OpaqueType(_, _) => panic!("constituent_types of opaque types are unknown!"),
79+
TyKind::AssociatedType(_, _) => {
80+
panic!("constituent_types of associated types are unknown!")
81+
}
8082
}
8183
}
8284

@@ -176,12 +178,16 @@ pub fn push_auto_trait_impls<I: Interner>(
176178
Ok(())
177179
}
178180

179-
// Unimplemented
180-
TyKind::OpaqueType(_, _) => Ok(()),
181-
TyKind::AssociatedType(_, _) => Ok(()),
181+
TyKind::OpaqueType(opaque_ty_id, _) => {
182+
push_auto_trait_impls_opaque(builder, auto_trait_id, *opaque_ty_id);
183+
Ok(())
184+
}
182185

183186
// No auto traits
184-
TyKind::Placeholder(_) | TyKind::Dyn(_) | TyKind::Alias(_) => Ok(()),
187+
TyKind::AssociatedType(_, _)
188+
| TyKind::Placeholder(_)
189+
| TyKind::Dyn(_)
190+
| TyKind::Alias(_) => Ok(()),
185191

186192
// app_ty implements AutoTrait if all constituents of app_ty implement AutoTrait
187193
_ => {
@@ -383,20 +389,56 @@ fn program_clauses_that_could_match<I: Interner>(
383389

384390
match goal {
385391
DomainGoal::Holds(WhereClause::Implemented(trait_ref)) => {
386-
let trait_id = trait_ref.trait_id;
392+
let self_ty = trait_ref.self_type_parameter(interner);
387393

394+
let trait_id = trait_ref.trait_id;
388395
let trait_datum = db.trait_datum(trait_id);
389396

390-
if trait_datum.is_non_enumerable_trait() || trait_datum.is_auto_trait() {
391-
let self_ty = trait_ref.self_type_parameter(interner);
397+
match self_ty.kind(interner) {
398+
TyKind::Alias(alias) => {
399+
// An alias could normalize to anything, including `dyn trait`
400+
// or an opaque type, so push a clause that asks for the
401+
// self type to be normalized and return.
402+
push_alias_implemented_clause(builder, trait_ref, alias);
403+
return Ok(clauses);
404+
}
392405

393-
if let TyKind::Alias(AliasTy::Opaque(opaque_ty)) = self_ty.kind(interner) {
394-
if trait_datum.is_auto_trait() {
395-
push_auto_trait_impls_opaque(builder, trait_id, opaque_ty.opaque_ty_id)
406+
_ if self_ty.is_general_var(interner, binders) => {
407+
if trait_datum.is_non_enumerable_trait() || trait_datum.is_auto_trait() {
408+
return Err(Floundered);
396409
}
397-
} else if self_ty.is_general_var(interner, binders) {
398-
return Err(Floundered);
399410
}
411+
412+
TyKind::OpaqueType(opaque_ty_id, _) => {
413+
db.opaque_ty_data(*opaque_ty_id)
414+
.to_program_clauses(builder, environment);
415+
}
416+
417+
TyKind::Dyn(_) => {
418+
// If the self type is a `dyn trait` type, generate program-clauses
419+
// that indicates that it implements its own traits.
420+
// FIXME: This is presently rather wasteful, in that we don't check that the
421+
// these program clauses we are generating are actually relevant to the goal
422+
// `goal` that we are actually *trying* to prove (though there is some later
423+
// code that will screen out irrelevant stuff).
424+
//
425+
// In other words, if we were trying to prove `Implemented(dyn
426+
// Fn(&u8): Clone)`, we would still generate two clauses that are
427+
// totally irrelevant to that goal, because they let us prove other
428+
// things but not `Clone`.
429+
dyn_ty::build_dyn_self_ty_clauses(db, builder, self_ty.clone())
430+
}
431+
432+
// We don't actually do anything here, but we need to record the types when logging
433+
TyKind::Adt(adt_id, _) => {
434+
let _ = db.adt_datum(*adt_id);
435+
}
436+
437+
TyKind::FnDef(fn_def_id, _) => {
438+
let _ = db.fn_def_datum(*fn_def_id);
439+
}
440+
441+
_ => {}
400442
}
401443

402444
// This is needed for the coherence related impls, as well
@@ -423,42 +465,6 @@ fn program_clauses_that_could_match<I: Interner>(
423465
})?;
424466
}
425467

426-
// If the self type is a `dyn trait` type, generate program-clauses
427-
// that indicates that it implements its own traits.
428-
// FIXME: This is presently rather wasteful, in that we don't check that the
429-
// these program clauses we are generating are actually relevant to the goal
430-
// `goal` that we are actually *trying* to prove (though there is some later
431-
// code that will screen out irrelevant stuff).
432-
//
433-
// In other words, if we were trying to prove `Implemented(dyn
434-
// Fn(&u8): Clone)`, we would still generate two clauses that are
435-
// totally irrelevant to that goal, because they let us prove other
436-
// things but not `Clone`.
437-
let self_ty = trait_ref.self_type_parameter(interner);
438-
if let TyKind::Dyn(_) = self_ty.kind(interner) {
439-
dyn_ty::build_dyn_self_ty_clauses(db, builder, self_ty.clone())
440-
}
441-
442-
match self_ty.kind(interner) {
443-
TyKind::OpaqueType(opaque_ty_id, _)
444-
| TyKind::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, .. })) => {
445-
db.opaque_ty_data(*opaque_ty_id)
446-
.to_program_clauses(builder, environment);
447-
}
448-
_ => {}
449-
}
450-
451-
// We don't actually do anything here, but we need to record the types it when logging
452-
match self_ty.kind(interner) {
453-
TyKind::Adt(adt_id, _) => {
454-
let _ = db.adt_datum(*adt_id);
455-
}
456-
TyKind::FnDef(fn_def_id, _) => {
457-
let _ = db.fn_def_datum(*fn_def_id);
458-
}
459-
_ => {}
460-
}
461-
462468
if let Some(well_known) = trait_datum.well_known {
463469
builtin_traits::add_builtin_program_clauses(
464470
db, builder, well_known, trait_ref, binders,
@@ -472,21 +478,26 @@ fn program_clauses_that_could_match<I: Interner>(
472478
.self_type_parameter(interner);
473479

474480
match trait_self_ty.kind(interner) {
475-
TyKind::OpaqueType(opaque_ty_id, _)
476-
| TyKind::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, .. })) => {
481+
TyKind::Alias(alias) => {
482+
// An alias could normalize to anything, including an
483+
// opaque type, so push a clause that asks for the self
484+
// type to be normalized and return.
485+
push_alias_alias_eq_clause(builder, proj, &alias_eq.ty, alias);
486+
return Ok(clauses);
487+
}
488+
TyKind::OpaqueType(opaque_ty_id, _) => {
477489
db.opaque_ty_data(*opaque_ty_id)
478490
.to_program_clauses(builder, environment);
479491
}
492+
// If the self type is a `dyn trait` type, generate program-clauses
493+
// for any associated type bindings it contains.
494+
// FIXME: see the fixme for the analogous code for Implemented goals.
495+
TyKind::Dyn(_) => {
496+
dyn_ty::build_dyn_self_ty_clauses(db, builder, trait_self_ty.clone())
497+
}
480498
_ => {}
481499
}
482500

483-
// If the self type is a `dyn trait` type, generate program-clauses
484-
// for any associated type bindings it contains.
485-
// FIXME: see the fixme for the analogous code for Implemented goals.
486-
if let TyKind::Dyn(_) = trait_self_ty.kind(interner) {
487-
dyn_ty::build_dyn_self_ty_clauses(db, builder, trait_self_ty.clone())
488-
}
489-
490501
db.associated_ty_data(proj.associated_ty_id)
491502
.to_program_clauses(builder, environment)
492503
}
@@ -702,6 +713,97 @@ fn push_program_clauses_for_associated_type_values_in_impls_of<I: Interner>(
702713
}
703714
}
704715

716+
fn push_alias_implemented_clause<I: Interner>(
717+
builder: &mut ClauseBuilder<'_, I>,
718+
trait_ref: &TraitRef<I>,
719+
alias: &AliasTy<I>,
720+
) {
721+
let interner = builder.interner();
722+
assert_eq!(
723+
*trait_ref.self_type_parameter(interner).kind(interner),
724+
TyKind::Alias(alias.clone())
725+
);
726+
727+
let binders = Binders::with_fresh_type_var(interner, |ty_var| ty_var);
728+
729+
// forall<..., T> {
730+
// <X as Y>::Z: Trait :- T: Trait, <X as Y>::Z == T
731+
// }
732+
builder.push_binders(&binders, |builder, bound_var| {
733+
let fresh_self_subst = Substitution::from_iter(
734+
interner,
735+
std::iter::once(bound_var.clone().cast(interner)).chain(
736+
trait_ref.substitution.as_slice(interner)[1..]
737+
.iter()
738+
.cloned(),
739+
),
740+
);
741+
let fresh_self_trait_ref = TraitRef {
742+
trait_id: trait_ref.trait_id,
743+
substitution: fresh_self_subst,
744+
};
745+
builder.push_clause(
746+
DomainGoal::Holds(WhereClause::Implemented(trait_ref.clone())),
747+
&[
748+
DomainGoal::Holds(WhereClause::Implemented(fresh_self_trait_ref)),
749+
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
750+
alias: alias.clone(),
751+
ty: bound_var,
752+
})),
753+
],
754+
);
755+
});
756+
}
757+
758+
fn push_alias_alias_eq_clause<I: Interner>(
759+
builder: &mut ClauseBuilder<'_, I>,
760+
projection_ty: &ProjectionTy<I>,
761+
ty: &Ty<I>,
762+
alias: &AliasTy<I>,
763+
) {
764+
let interner = builder.interner();
765+
assert_eq!(
766+
*projection_ty.self_type_parameter(interner).kind(interner),
767+
TyKind::Alias(alias.clone())
768+
);
769+
770+
let binders = Binders::with_fresh_type_var(interner, |ty_var| ty_var);
771+
772+
// forall<..., T> {
773+
// <<X as Y>::A as Z>::B == U :- <T as Z>::B == U, <X as Y>::A == T
774+
// }
775+
builder.push_binders(&binders, |builder, bound_var| {
776+
let fresh_self_subst = Substitution::from_iter(
777+
interner,
778+
std::iter::once(bound_var.clone().cast(interner)).chain(
779+
projection_ty.substitution.as_slice(interner)[1..]
780+
.iter()
781+
.cloned(),
782+
),
783+
);
784+
let fresh_alias = AliasTy::Projection(ProjectionTy {
785+
associated_ty_id: projection_ty.associated_ty_id,
786+
substitution: fresh_self_subst,
787+
});
788+
builder.push_clause(
789+
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
790+
alias: AliasTy::Projection(projection_ty.clone()),
791+
ty: ty.clone(),
792+
})),
793+
&[
794+
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
795+
alias: fresh_alias,
796+
ty: ty.clone(),
797+
})),
798+
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
799+
alias: alias.clone(),
800+
ty: bound_var,
801+
})),
802+
],
803+
);
804+
});
805+
}
806+
705807
/// Examine `T` and push clauses that may be relevant to proving the
706808
/// following sorts of goals (and maybe others):
707809
///
@@ -764,7 +866,37 @@ fn match_ty<I: Interner>(
764866
builder.push_fact(WellFormed::Ty(ty.clone()));
765867
}
766868
TyKind::BoundVar(_) | TyKind::InferenceVar(_, _) => return Err(Floundered),
767-
TyKind::Dyn(_) => {}
869+
TyKind::Dyn(dyn_ty) => {
870+
// FIXME(#203)
871+
// - Object safety? (not needed with RFC 2027)
872+
// - Implied bounds
873+
// - Bounds on the associated types
874+
// - Checking that all associated types are specified, including
875+
// those on supertraits.
876+
// - For trait objects with GATs, check that the bounds are fully
877+
// general (`dyn for<'a> StreamingIterator<Item<'a> = &'a ()>` is OK,
878+
// `dyn StreamingIterator<Item<'static> = &'static ()>` is not).
879+
let bounds = dyn_ty
880+
.bounds
881+
.substitute(interner, &[ty.clone().cast::<GenericArg<I>>(interner)]);
882+
883+
let mut wf_goals = Vec::new();
884+
885+
wf_goals.extend(bounds.iter(interner).flat_map(|bound| {
886+
bound.map_ref(|bound| -> Vec<_> {
887+
match bound {
888+
WhereClause::Implemented(trait_ref) => {
889+
vec![DomainGoal::WellFormed(WellFormed::Trait(trait_ref.clone()))]
890+
}
891+
WhereClause::AliasEq(_)
892+
| WhereClause::LifetimeOutlives(_)
893+
| WhereClause::TypeOutlives(_) => vec![],
894+
}
895+
})
896+
}));
897+
898+
builder.push_clause(WellFormed::Ty(ty.clone()), wf_goals);
899+
}
768900
})
769901
}
770902

tests/test/opaque_types.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,40 @@ fn opaque_auto_traits() {
205205
}
206206
}
207207
}
208+
209+
#[test]
210+
fn opaque_auto_traits_indirect() {
211+
test! {
212+
program {
213+
struct Bar { }
214+
struct Baz { }
215+
trait Trait { }
216+
217+
impl Trait for Bar { }
218+
impl Trait for Baz { }
219+
220+
#[auto]
221+
trait Send { }
222+
trait SendDerived where Self: Send { }
223+
224+
impl<T> SendDerived for T where T: Send { }
225+
226+
impl !Send for Baz { }
227+
228+
opaque type Opaque1: Trait = Bar;
229+
opaque type Opaque2: Trait = Baz;
230+
}
231+
232+
goal {
233+
Opaque1: SendDerived
234+
} yields {
235+
"Unique"
236+
}
237+
238+
goal {
239+
Opaque2: SendDerived
240+
} yields {
241+
"No possible solution"
242+
}
243+
}
244+
}

0 commit comments

Comments
 (0)