Skip to content

Commit d3e2ade

Browse files
committed
everything working 🎆
1 parent 297aab9 commit d3e2ade

File tree

2 files changed

+124
-27
lines changed

2 files changed

+124
-27
lines changed

chalk-solve/src/wf.rs

Lines changed: 121 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::fmt;
1+
use std::{fmt, iter};
22

33
use crate::ext::*;
44
use crate::goal_builder::GoalBuilder;
@@ -252,15 +252,27 @@ fn impl_header_wf_goal<I: Interner>(
252252

253253
let mut gb = GoalBuilder::new(db);
254254
// forall<P0...Pn> {...}
255-
Some(
256-
gb.forall(&impl_fields, (), |gb, _, (trait_ref, where_clauses), ()| {
255+
Some(gb.forall(
256+
&impl_fields,
257+
impl_id,
258+
|gb, _, (trait_ref, where_clauses), impl_id| {
257259
let interner = gb.interner();
258260

259-
let trait_constraint_goal = compute_well_known_impl_constraint(gb.db(), &trait_ref, where_clauses);
260-
261261
// if (WC && input types are well formed) { ... }
262-
let impl_wf = impl_wf_environment(interner, &where_clauses, &trait_ref);
263-
gb.implies(impl_wf, |gb| {
262+
let impl_wf = ProgramClauses::from(
263+
interner,
264+
impl_wf_environment(interner, &where_clauses, &trait_ref),
265+
);
266+
267+
let trait_constraint_goal = compute_well_known_impl_constraint(
268+
gb.db(),
269+
impl_id,
270+
&impl_wf,
271+
&trait_ref,
272+
where_clauses,
273+
);
274+
275+
let well_formed_goal = gb.implies(impl_wf.iter(interner), |gb| {
264276
// We retrieve all the input types of the where clauses appearing on the trait impl,
265277
// e.g. in:
266278
// ```
@@ -277,13 +289,16 @@ fn impl_header_wf_goal<I: Interner>(
277289
let goals = types
278290
.into_iter()
279291
.map(|ty| ty.well_formed().cast(interner))
280-
.chain(Some((*trait_ref).clone().well_formed().cast(interner)))
281-
.chain(trait_constraint_goal.into_iter());
292+
.chain(Some((*trait_ref).clone().well_formed().cast(interner)));
282293

283294
gb.all::<_, Goal<I>>(goals)
284-
})
285-
}),
286-
)
295+
});
296+
297+
gb.all::<_, Goal<I>>(
298+
iter::once(well_formed_goal).chain(trait_constraint_goal.into_iter()),
299+
)
300+
},
301+
))
287302
}
288303

289304
/// Creates the conditions that an impl (and its contents of an impl)
@@ -445,14 +460,22 @@ fn compute_assoc_ty_goal<I: Interner>(
445460
))
446461
}
447462

448-
fn compute_well_known_impl_constraint<I: Interner>(db: &dyn RustIrDatabase<I>, trait_ref: &TraitRef<I>, where_clause: &[Binders<WhereClause<I>>]) -> Option<Goal<I>> {
463+
fn compute_well_known_impl_constraint<I: Interner>(
464+
db: &dyn RustIrDatabase<I>,
465+
impl_id: ImplId<I>,
466+
impl_wf: &ProgramClauses<I>,
467+
trait_ref: &TraitRef<I>,
468+
where_clause: &[Binders<WhereClause<I>>],
469+
) -> Option<Goal<I>> {
449470
let interner = db.interner();
450471

451472
match db.trait_datum(trait_ref.trait_id).well_known? {
452473
// You can't add a manual implementation of Sized
453474
WellKnownTrait::SizedTrait => Some(GoalData::CannotProve(()).intern(interner)),
454-
WellKnownTrait::CopyTrait => compute_copy_impl_constraint(db, trait_ref, where_clause),
455-
WellKnownTrait::DropTrait => compute_drop_impl_constraint(db, trait_ref, where_clause),
475+
WellKnownTrait::CopyTrait => compute_copy_impl_constraint(db, impl_wf, trait_ref),
476+
WellKnownTrait::DropTrait => {
477+
compute_drop_impl_constraint(db, impl_id, trait_ref, where_clause)
478+
}
456479
WellKnownTrait::CloneTrait => None,
457480
}
458481
}
@@ -492,14 +515,12 @@ fn compute_struct_sized_constraint<I: Interner>(
492515
/// 2) don't have a Drop impl
493516
fn compute_copy_impl_constraint<I: Interner>(
494517
db: &dyn RustIrDatabase<I>,
518+
impl_wf: &ProgramClauses<I>,
495519
trait_ref: &TraitRef<I>,
496-
_where_clause: &[Binders<WhereClause<I>>],
497520
) -> Option<Goal<I>> {
498521
let interner = db.interner();
499522

500523
let ty = trait_ref.self_type_parameter(interner);
501-
502-
let copy_trait = db.well_known_trait_id(WellKnownTrait::CopyTrait)?;
503524
let ty_data = ty.data(interner);
504525

505526
let (struct_id, substitution) = match ty_data {
@@ -532,20 +553,98 @@ fn compute_copy_impl_constraint<I: Interner>(
532553
.into_iter()
533554
.map(|f| {
534555
TraitRef {
535-
trait_id: copy_trait,
556+
trait_id: trait_ref.trait_id,
536557
substitution: Substitution::from1(interner, f),
537558
}
538559
.cast(interner)
539560
})
540561
.chain(neg_drop_goal.into_iter());
541562

542-
Some(Goal::all(interner, goals))
563+
Some(GoalData::Implies(impl_wf.clone(), Goal::all(interner, goals)).intern(interner))
543564
}
544565

566+
/// Computes goal to prove constraints on a Drop implementation
567+
/// Drop implementation is considered well-formed if:
568+
/// a) it's implemented on an ADT
569+
/// b) The generic parameters of the impl's type must all be parameters
570+
/// of the Drop impl itself (i.e., no specialization like
571+
/// `impl Drop for S<Foo> {...}` is allowed).
572+
/// c) Any bounds on the genereic parameters of the impl must be
573+
/// deductible from the bounds imposed by the struct definition
574+
/// (i.e. the implementation must be exactly as generic as the ADT definition).
545575
fn compute_drop_impl_constraint<I: Interner>(
546576
db: &dyn RustIrDatabase<I>,
577+
impl_id: ImplId<I>,
547578
trait_ref: &TraitRef<I>,
548-
where_clauses: &[Binders<WhereClause<I>>]
579+
where_clauses: &[QuantifiedWhereClause<I>],
549580
) -> Option<Goal<I>> {
550-
None
581+
let interner = db.interner();
582+
583+
let ty = trait_ref.self_type_parameter(interner);
584+
let ty_data = ty.data(interner);
585+
586+
let (struct_id, substitution) = match ty_data {
587+
TyData::Apply(ApplicationTy {
588+
name: TypeName::Struct(struct_id),
589+
substitution,
590+
}) => (*struct_id, substitution),
591+
_ => return Some(GoalData::CannotProve(()).intern(interner)),
592+
};
593+
594+
let mut gb = GoalBuilder::new(db);
595+
596+
let struct_datum = db.struct_datum(struct_id);
597+
let struct_name = struct_datum.name(interner);
598+
599+
let implied_by_struct_def_goal = gb.implies(
600+
struct_datum
601+
.binders
602+
.map_ref(|b| &b.where_clauses)
603+
.substitute(interner, substitution)
604+
.into_iter()
605+
.map(move |qwc| {
606+
qwc.into_from_env_goal(interner)
607+
.cast::<ProgramClause<I>>(interner)
608+
}),
609+
|gb| {
610+
gb.all(
611+
where_clauses
612+
.iter()
613+
.map(|wc| wc.clone().into_well_formed_goal(interner)),
614+
)
615+
},
616+
);
617+
618+
let eq_goal = gb.forall(
619+
&struct_datum.binders,
620+
(struct_name, impl_id),
621+
|gb, substitution, _, (struct_name, impl_id)| {
622+
let interner = gb.interner();
623+
624+
let impl_datum = gb.db().impl_datum(impl_id);
625+
let def_struct: Ty<I> = ApplicationTy {
626+
name: struct_name,
627+
substitution,
628+
}
629+
.cast(interner)
630+
.intern(interner);
631+
632+
gb.exists(
633+
&impl_datum
634+
.binders
635+
.map_ref(|b| b.trait_ref.self_type_parameter(interner)),
636+
def_struct,
637+
|gb, _, impl_struct, def_struct| {
638+
let interner = gb.interner();
639+
GoalData::EqGoal(EqGoal {
640+
a: ParameterData::Ty(def_struct).intern(interner),
641+
b: ParameterData::Ty(impl_struct.clone()).intern(interner),
642+
})
643+
.intern(interner)
644+
},
645+
)
646+
},
647+
);
648+
649+
Some(gb.all([implied_by_struct_def_goal, eq_goal].iter()))
551650
}

tests/test/wf_lowering.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -721,12 +721,10 @@ fn copy_constraints() {
721721
#[lang(drop)]
722722
trait Drop { }
723723

724-
struct S<T1, T2> where T1: Copy, T2: Copy {
725-
t1: T1,
726-
t2: T2
727-
}
724+
struct S<T> {}
725+
struct F {}
728726

729-
impl<T1, T2> Copy for S<T1, T2> { }
727+
impl<T> Drop for S<T> {}
730728
} error_msg {
731729
""
732730
}

0 commit comments

Comments
 (0)