1use std::ops::ControlFlow;
2use std::{fmt, iter};
3
4use crate::{
5 ext::*, goal_builder::GoalBuilder, rust_ir::*, solve::Solver, split::Split, RustIrDatabase,
6};
7use chalk_ir::{
8 cast::*,
9 fold::shift::Shift,
10 interner::Interner,
11 visit::{TypeVisitable, TypeVisitor},
12 *,
13};
14use tracing::debug;
15
16#[derive(Debug)]
17pub enum WfError<I: Interner> {
18 IllFormedTypeDecl(chalk_ir::AdtId<I>),
19 IllFormedOpaqueTypeDecl(chalk_ir::OpaqueTyId<I>),
20 IllFormedTraitImpl(chalk_ir::TraitId<I>),
21}
22
23impl<I: Interner> fmt::Display for WfError<I> {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 WfError::IllFormedTypeDecl(id) => write!(
27 f,
28 "type declaration `{:?}` does not meet well-formedness requirements",
29 id
30 ),
31 WfError::IllFormedOpaqueTypeDecl(id) => write!(
32 f,
33 "opaque type declaration `{:?}` does not meet well-formedness requirements",
34 id
35 ),
36 WfError::IllFormedTraitImpl(id) => write!(
37 f,
38 "trait impl for `{:?}` does not meet well-formedness requirements",
39 id
40 ),
41 }
42 }
43}
44
45impl<I: Interner> std::error::Error for WfError<I> {}
46
47pub struct WfSolver<'a, I: Interner> {
48 db: &'a dyn RustIrDatabase<I>,
49 solver_builder: &'a dyn Fn() -> Box<dyn Solver<I>>,
50}
51
52struct InputTypeCollector<I: Interner> {
53 types: Vec<Ty<I>>,
54 interner: I,
55}
56
57impl<I: Interner> InputTypeCollector<I> {
58 fn new(interner: I) -> Self {
59 Self {
60 types: Vec::new(),
61 interner,
62 }
63 }
64
65 fn types_in(interner: I, value: impl TypeVisitable<I>) -> Vec<Ty<I>> {
66 let mut collector = Self::new(interner);
67 value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
68 collector.types
69 }
70}
71
72impl<I: Interner> TypeVisitor<I> for InputTypeCollector<I> {
73 type BreakTy = ();
74 fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy> {
75 self
76 }
77
78 fn interner(&self) -> I {
79 self.interner
80 }
81
82 fn visit_where_clause(
83 &mut self,
84 where_clause: &WhereClause<I>,
85 outer_binder: DebruijnIndex,
86 ) -> ControlFlow<()> {
87 match where_clause {
88 WhereClause::AliasEq(alias_eq) => alias_eq
89 .alias
90 .clone()
91 .intern(self.interner)
92 .visit_with(self, outer_binder),
93 WhereClause::Implemented(trait_ref) => trait_ref.visit_with(self, outer_binder),
94 WhereClause::TypeOutlives(TypeOutlives { ty, .. }) => ty.visit_with(self, outer_binder),
95 WhereClause::LifetimeOutlives(..) => ControlFlow::Continue(()),
96 }
97 }
98
99 fn visit_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> ControlFlow<()> {
100 let interner = self.interner();
101
102 let mut push_ty = || {
103 self.types
104 .push(ty.clone().shifted_out_to(interner, outer_binder).unwrap())
105 };
106 match ty.kind(interner) {
107 TyKind::Adt(id, substitution) => {
108 push_ty();
109 id.visit_with(self, outer_binder);
110 substitution.visit_with(self, outer_binder)
111 }
112 TyKind::AssociatedType(assoc_ty, substitution) => {
113 push_ty();
114 assoc_ty.visit_with(self, outer_binder);
115 substitution.visit_with(self, outer_binder)
116 }
117 TyKind::Scalar(scalar) => {
118 push_ty();
119 scalar.visit_with(self, outer_binder)
120 }
121 TyKind::Str => {
122 push_ty();
123 ControlFlow::Continue(())
124 }
125 TyKind::Tuple(arity, substitution) => {
126 push_ty();
127 arity.visit_with(self, outer_binder);
128 substitution.visit_with(self, outer_binder)
129 }
130 TyKind::OpaqueType(opaque_ty, substitution) => {
131 push_ty();
132 opaque_ty.visit_with(self, outer_binder);
133 substitution.visit_with(self, outer_binder)
134 }
135 TyKind::Slice(substitution) => {
136 push_ty();
137 substitution.visit_with(self, outer_binder)
138 }
139 TyKind::FnDef(fn_def, substitution) => {
140 push_ty();
141 fn_def.visit_with(self, outer_binder);
142 substitution.visit_with(self, outer_binder)
143 }
144 TyKind::Ref(mutability, lifetime, ty) => {
145 push_ty();
146 mutability.visit_with(self, outer_binder);
147 lifetime.visit_with(self, outer_binder);
148 ty.visit_with(self, outer_binder)
149 }
150 TyKind::Raw(mutability, substitution) => {
151 push_ty();
152 mutability.visit_with(self, outer_binder);
153 substitution.visit_with(self, outer_binder)
154 }
155 TyKind::Never => {
156 push_ty();
157 ControlFlow::Continue(())
158 }
159 TyKind::Array(ty, const_) => {
160 push_ty();
161 ty.visit_with(self, outer_binder);
162 const_.visit_with(self, outer_binder)
163 }
164 TyKind::Closure(_id, substitution) => {
165 push_ty();
166 substitution.visit_with(self, outer_binder)
167 }
168 TyKind::Coroutine(_coroutine, substitution) => {
169 push_ty();
170 substitution.visit_with(self, outer_binder)
171 }
172 TyKind::CoroutineWitness(_witness, substitution) => {
173 push_ty();
174 substitution.visit_with(self, outer_binder)
175 }
176 TyKind::Foreign(_foreign_ty) => {
177 push_ty();
178 ControlFlow::Continue(())
179 }
180 TyKind::Error => {
181 push_ty();
182 ControlFlow::Continue(())
183 }
184
185 TyKind::Dyn(clauses) => {
186 push_ty();
187 clauses.visit_with(self, outer_binder)
188 }
189
190 TyKind::Alias(AliasTy::Projection(proj)) => {
191 push_ty();
192 proj.visit_with(self, outer_binder)
193 }
194
195 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
196 push_ty();
197 opaque_ty.visit_with(self, outer_binder)
198 }
199
200 TyKind::Placeholder(_) => {
201 push_ty();
202 ControlFlow::Continue(())
203 }
204
205 TyKind::BoundVar(..) => ControlFlow::Continue(()),
208
209 TyKind::Function(..) => ControlFlow::Continue(()),
214
215 TyKind::InferenceVar(..) => {
216 panic!("unexpected inference variable in wf rules: {:?}", ty)
217 }
218 }
219 }
220}
221
222impl<'a, I> WfSolver<'a, I>
223where
224 I: Interner,
225{
226 pub fn new(
228 db: &'a dyn RustIrDatabase<I>,
229 solver_builder: &'a dyn Fn() -> Box<dyn Solver<I>>,
230 ) -> Self {
231 Self { db, solver_builder }
232 }
233
234 pub fn verify_adt_decl(&self, adt_id: AdtId<I>) -> Result<(), WfError<I>> {
235 let interner = self.db.interner();
236
237 let adt_datum = self.db.adt_datum(adt_id);
245 let is_enum = adt_datum.kind == AdtKind::Enum;
246
247 let mut gb = GoalBuilder::new(self.db);
248 let adt_data = adt_datum
249 .binders
250 .map_ref(|b| (&b.variants, &b.where_clauses));
251
252 let wg_goal = gb.forall(
256 &adt_data,
257 is_enum,
258 |gb, _, (variants, where_clauses), is_enum| {
259 let interner = gb.interner();
260
261 gb.implies(
263 where_clauses
264 .iter()
265 .cloned()
266 .map(|wc| wc.into_from_env_goal(interner)),
267 |gb| {
268 let sub_goals: Vec<_> = variants
269 .iter()
270 .flat_map(|variant| {
271 let fields = &variant.fields;
272
273 let sized_constraint_goal =
277 WfWellKnownConstraints::struct_sized_constraint(
278 gb.db(),
279 fields,
280 is_enum,
281 );
282
283 let types = InputTypeCollector::types_in(
285 gb.interner(),
286 (&fields, &where_clauses),
287 );
288
289 types
290 .into_iter()
291 .map(|ty| ty.well_formed().cast(interner))
292 .chain(sized_constraint_goal.into_iter())
293 })
294 .collect();
295
296 gb.all(sub_goals)
297 },
298 )
299 },
300 );
301
302 let wg_goal = wg_goal.into_closed_goal(interner);
303 let mut fresh_solver = (self.solver_builder)();
304 let is_legal = fresh_solver.has_unique_solution(self.db, &wg_goal);
305
306 if !is_legal {
307 Err(WfError::IllFormedTypeDecl(adt_id))
308 } else {
309 Ok(())
310 }
311 }
312
313 pub fn verify_trait_impl(&self, impl_id: ImplId<I>) -> Result<(), WfError<I>> {
314 let interner = self.db.interner();
315
316 let impl_datum = self.db.impl_datum(impl_id);
317 let trait_id = impl_datum.trait_id();
318
319 let impl_goal = Goal::all(
320 interner,
321 impl_header_wf_goal(self.db, impl_id).into_iter().chain(
322 impl_datum
323 .associated_ty_value_ids
324 .iter()
325 .filter_map(|&id| compute_assoc_ty_goal(self.db, id)),
326 ),
327 );
328
329 if let Some(well_known) = self.db.trait_datum(trait_id).well_known {
330 self.verify_well_known_impl(impl_id, well_known)?
331 }
332
333 debug!("WF trait goal: {:?}", impl_goal);
334
335 let mut fresh_solver = (self.solver_builder)();
336 let is_legal =
337 fresh_solver.has_unique_solution(self.db, &impl_goal.into_closed_goal(interner));
338
339 if is_legal {
340 Ok(())
341 } else {
342 Err(WfError::IllFormedTraitImpl(trait_id))
343 }
344 }
345
346 pub fn verify_opaque_ty_decl(&self, opaque_ty_id: OpaqueTyId<I>) -> Result<(), WfError<I>> {
347 let interner = self.db.interner();
352
353 let mut gb = GoalBuilder::new(self.db);
354
355 let datum = self.db.opaque_ty_data(opaque_ty_id);
356 let bound = &datum.bound;
357
358 let goal = gb.forall(bound, opaque_ty_id, |gb, _, bound, opaque_ty_id| {
362 let interner = gb.interner();
363
364 let subst = Substitution::from1(interner, gb.db().hidden_opaque_type(opaque_ty_id));
365
366 let bounds = bound.bounds.clone().substitute(interner, &subst);
367 let where_clauses = bound.where_clauses.clone().substitute(interner, &subst);
368
369 let clauses = where_clauses
370 .iter()
371 .cloned()
372 .map(|wc| wc.into_from_env_goal(interner));
373
374 gb.implies(clauses, |gb| {
376 let interner = gb.interner();
377
378 gb.all(
380 bounds
381 .iter()
382 .cloned()
383 .map(|b| b.into_well_formed_goal(interner)),
384 )
385 })
386 });
387
388 debug!("WF opaque type goal: {:#?}", goal);
389
390 let mut new_solver = (self.solver_builder)();
391 let is_legal = new_solver.has_unique_solution(self.db, &goal.into_closed_goal(interner));
392
393 if is_legal {
394 Ok(())
395 } else {
396 Err(WfError::IllFormedOpaqueTypeDecl(opaque_ty_id))
397 }
398 }
399
400 pub fn verify_well_known_impl(
402 &self,
403 impl_id: ImplId<I>,
404 well_known: WellKnownTrait,
405 ) -> Result<(), WfError<I>> {
406 let mut solver = (self.solver_builder)();
407 let impl_datum = self.db.impl_datum(impl_id);
408
409 let is_legal = match well_known {
410 WellKnownTrait::Copy => {
411 WfWellKnownConstraints::copy_impl_constraint(&mut *solver, self.db, &impl_datum)
412 }
413 WellKnownTrait::Drop => {
414 WfWellKnownConstraints::drop_impl_constraint(&mut *solver, self.db, &impl_datum)
415 }
416 WellKnownTrait::CoerceUnsized => {
417 WfWellKnownConstraints::coerce_unsized_impl_constraint(
418 &mut *solver,
419 self.db,
420 &impl_datum,
421 )
422 }
423 WellKnownTrait::DispatchFromDyn => {
424 WfWellKnownConstraints::dispatch_from_dyn_constraint(
425 &mut *solver,
426 self.db,
427 &impl_datum,
428 )
429 }
430 WellKnownTrait::Clone | WellKnownTrait::Unpin | WellKnownTrait::Future => true,
431 WellKnownTrait::Fn
433 | WellKnownTrait::FnOnce
434 | WellKnownTrait::FnMut
435 | WellKnownTrait::AsyncFn
436 | WellKnownTrait::AsyncFnOnce
437 | WellKnownTrait::AsyncFnMut
438 | WellKnownTrait::Unsize
439 | WellKnownTrait::Sized
440 | WellKnownTrait::DiscriminantKind
441 | WellKnownTrait::Coroutine
442 | WellKnownTrait::Pointee
443 | WellKnownTrait::Tuple
444 | WellKnownTrait::FnPtr => false,
445 };
446
447 if is_legal {
448 Ok(())
449 } else {
450 Err(WfError::IllFormedTraitImpl(impl_datum.trait_id()))
451 }
452 }
453}
454
455fn impl_header_wf_goal<I: Interner>(
456 db: &dyn RustIrDatabase<I>,
457 impl_id: ImplId<I>,
458) -> Option<Goal<I>> {
459 let impl_datum = db.impl_datum(impl_id);
460
461 if !impl_datum.is_positive() {
462 return None;
463 }
464
465 let impl_fields = impl_datum
466 .binders
467 .map_ref(|v| (&v.trait_ref, &v.where_clauses));
468
469 let mut gb = GoalBuilder::new(db);
470 let well_formed_goal = gb.forall(&impl_fields, (), |gb, _, (trait_ref, where_clauses), ()| {
472 let interner = gb.interner();
473
474 gb.implies(
476 impl_wf_environment(interner, where_clauses, trait_ref),
477 |gb| {
478 let types = InputTypeCollector::types_in(gb.interner(), &where_clauses);
487
488 debug!(input_types=?types);
491 let goals = types
492 .into_iter()
493 .map(|ty| ty.well_formed().cast(interner))
494 .chain(Some((*trait_ref).clone().well_formed().cast(interner)));
495
496 gb.all::<_, Goal<I>>(goals)
497 },
498 )
499 });
500
501 Some(well_formed_goal)
502}
503
504fn impl_wf_environment<'i, I: Interner>(
507 interner: I,
508 where_clauses: &'i [QuantifiedWhereClause<I>],
509 trait_ref: &'i TraitRef<I>,
510) -> impl Iterator<Item = ProgramClause<I>> + 'i {
511 let wc = where_clauses
513 .iter()
514 .cloned()
515 .map(move |qwc| qwc.into_from_env_goal(interner).cast(interner));
516
517 let types = InputTypeCollector::types_in(interner, trait_ref);
530
531 let types_wf = types
532 .into_iter()
533 .map(move |ty| ty.into_from_env_goal(interner).cast(interner));
534
535 wc.chain(types_wf)
536}
537
538fn compute_assoc_ty_goal<I: Interner>(
566 db: &dyn RustIrDatabase<I>,
567 assoc_ty_id: AssociatedTyValueId<I>,
568) -> Option<Goal<I>> {
569 let mut gb = GoalBuilder::new(db);
570 let assoc_ty = &db.associated_ty_value(assoc_ty_id);
571
572 Some(gb.forall(
574 &assoc_ty.value.map_ref(|v| &v.ty),
575 assoc_ty_id,
576 |gb, assoc_ty_substitution, value_ty, assoc_ty_id| {
577 let interner = gb.interner();
578 let db = gb.db();
579
580 let assoc_ty = &db.associated_ty_value(assoc_ty_id);
587
588 let (impl_parameters, projection) = db
589 .impl_parameters_and_projection_from_associated_ty_value(
590 assoc_ty_substitution.as_slice(interner),
591 assoc_ty,
592 );
593
594 let impl_id = assoc_ty.impl_id;
596 let impl_datum = &db.impl_datum(impl_id);
597 let ImplDatumBound {
598 trait_ref: impl_trait_ref,
599 where_clauses: impl_where_clauses,
600 } = impl_datum
601 .binders
602 .clone()
603 .substitute(interner, impl_parameters);
604 let impl_wf_clauses =
605 impl_wf_environment(interner, &impl_where_clauses, &impl_trait_ref);
606 gb.implies(impl_wf_clauses, |gb| {
607 let assoc_ty_datum = db.associated_ty_data(projection.associated_ty_id);
621 let AssociatedTyDatumBound {
622 bounds: defn_bounds,
623 where_clauses: defn_where_clauses,
624 } = assoc_ty_datum
625 .binders
626 .clone()
627 .substitute(interner, &projection.substitution);
628
629 gb.implies(
631 defn_where_clauses
632 .iter()
633 .cloned()
634 .map(|qwc| qwc.into_from_env_goal(interner)),
635 |gb| {
636 let types = InputTypeCollector::types_in(gb.interner(), value_ty);
637
638 let wf_goals = types
640 .into_iter()
641 .map(|ty| ty.well_formed())
642 .casted(interner);
643
644 let bound_goals = defn_bounds
652 .iter()
653 .cloned()
654 .flat_map(|qb| qb.into_where_clauses(interner, (*value_ty).clone()))
655 .map(|qwc| qwc.into_well_formed_goal(interner))
656 .casted(interner);
657
658 gb.all::<_, Goal<I>>(wf_goals.chain(bound_goals))
660 },
661 )
662 })
663 },
664 ))
665}
666
667struct WfWellKnownConstraints;
670
671impl WfWellKnownConstraints {
672 pub fn struct_sized_constraint<I: Interner>(
676 db: &dyn RustIrDatabase<I>,
677 fields: &[Ty<I>],
678 size_all: bool,
679 ) -> Option<Goal<I>> {
680 let excluded = if size_all { 0 } else { 1 };
681
682 if fields.len() <= excluded {
683 return None;
684 }
685
686 let interner = db.interner();
687
688 let sized_trait = db.well_known_trait_id(WellKnownTrait::Sized)?;
689
690 Some(Goal::all(
691 interner,
692 fields[..fields.len() - excluded].iter().map(|ty| {
693 TraitRef {
694 trait_id: sized_trait,
695 substitution: Substitution::from1(interner, ty.clone()),
696 }
697 .cast(interner)
698 }),
699 ))
700 }
701
702 fn copy_impl_constraint<I: Interner>(
709 solver: &mut dyn Solver<I>,
710 db: &dyn RustIrDatabase<I>,
711 impl_datum: &ImplDatum<I>,
712 ) -> bool {
713 let interner = db.interner();
714
715 let mut gb = GoalBuilder::new(db);
716
717 let impl_fields = impl_datum
718 .binders
719 .map_ref(|v| (&v.trait_ref, &v.where_clauses));
720
721 match impl_datum
724 .binders
725 .skip_binders()
726 .trait_ref
727 .self_type_parameter(interner)
728 .kind(interner)
729 {
730 TyKind::Scalar(_)
731 | TyKind::Raw(_, _)
732 | TyKind::Ref(Mutability::Not, _, _)
733 | TyKind::Never => return true,
734
735 TyKind::Adt(_, _) => (),
736
737 _ => return false,
738 };
739
740 let well_formed_goal =
742 gb.forall(&impl_fields, (), |gb, _, (trait_ref, where_clauses), ()| {
743 let interner = gb.interner();
744
745 let ty = trait_ref.self_type_parameter(interner);
746
747 let (adt_id, substitution) = match ty.kind(interner) {
748 TyKind::Adt(adt_id, substitution) => (*adt_id, substitution),
749
750 _ => unreachable!(),
751 };
752
753 gb.implies(
755 impl_wf_environment(interner, where_clauses, trait_ref),
756 |gb| -> Goal<I> {
757 let db = gb.db();
758
759 let neg_drop_goal =
761 db.well_known_trait_id(WellKnownTrait::Drop)
762 .map(|drop_trait_id| {
763 TraitRef {
764 trait_id: drop_trait_id,
765 substitution: Substitution::from1(interner, ty.clone()),
766 }
767 .cast::<Goal<I>>(interner)
768 .negate(interner)
769 });
770
771 let adt_datum = db.adt_datum(adt_id);
772
773 let goals = adt_datum
774 .binders
775 .map_ref(|b| &b.variants)
776 .cloned()
777 .substitute(interner, substitution)
778 .into_iter()
779 .flat_map(|v| {
780 v.fields.into_iter().map(|f| {
781 TraitRef {
783 trait_id: trait_ref.trait_id,
784 substitution: Substitution::from1(interner, f),
785 }
786 .cast(interner)
787 })
788 })
789 .chain(neg_drop_goal.into_iter());
790 gb.all(goals)
791 },
792 )
793 });
794
795 solver.has_unique_solution(db, &well_formed_goal.into_closed_goal(interner))
796 }
797
798 fn drop_impl_constraint<I: Interner>(
833 solver: &mut dyn Solver<I>,
834 db: &dyn RustIrDatabase<I>,
835 impl_datum: &ImplDatum<I>,
836 ) -> bool {
837 let interner = db.interner();
838
839 let adt_id = match impl_datum.self_type_adt_id(interner) {
840 Some(id) => id,
841 None => return false,
843 };
844
845 let mut gb = GoalBuilder::new(db);
846
847 let adt_datum = db.adt_datum(adt_id);
848
849 let impl_fields = impl_datum
850 .binders
851 .map_ref(|v| (&v.trait_ref, &v.where_clauses));
852
853 let implied_by_adt_def_goal =
855 gb.forall(&impl_fields, (), |gb, _, (trait_ref, where_clauses), ()| {
856 let interner = gb.interner();
857
858 gb.implies(
860 iter::once(
861 FromEnv::Ty(trait_ref.self_type_parameter(interner))
862 .cast::<DomainGoal<I>>(interner),
863 ),
864 |gb| {
865 gb.all(
867 where_clauses
868 .iter()
869 .map(|wc| wc.clone().into_well_formed_goal(interner)),
870 )
871 },
872 )
873 });
874
875 let impl_self_ty = impl_datum
876 .binders
877 .map_ref(|b| b.trait_ref.self_type_parameter(interner));
878
879 let eq_goal = gb.forall(
881 &adt_datum.binders,
882 (adt_id, impl_self_ty),
883 |gb, substitution, _, (adt_id, impl_self_ty)| {
884 let interner = gb.interner();
885
886 let def_adt = TyKind::Adt(adt_id, substitution).intern(interner);
887
888 gb.exists(&impl_self_ty, def_adt, |gb, _, impl_adt, def_adt| {
890 let interner = gb.interner();
891
892 GoalData::EqGoal(EqGoal {
894 a: GenericArgData::Ty(def_adt).intern(interner),
895 b: GenericArgData::Ty(impl_adt.clone()).intern(interner),
896 })
897 .intern(interner)
898 })
899 },
900 );
901
902 let well_formed_goal = gb.all([implied_by_adt_def_goal, eq_goal].iter());
903
904 solver.has_unique_solution(db, &well_formed_goal.into_closed_goal(interner))
905 }
906
907 fn coerce_unsized_impl_constraint<I: Interner>(
942 solver: &mut dyn Solver<I>,
943 db: &dyn RustIrDatabase<I>,
944 impl_datum: &ImplDatum<I>,
945 ) -> bool {
946 let interner = db.interner();
947 let mut gb = GoalBuilder::new(db);
948
949 let (binders, impl_datum) = impl_datum.binders.as_ref().into();
950
951 let trait_ref: &TraitRef<I> = &impl_datum.trait_ref;
952
953 let source = trait_ref.self_type_parameter(interner);
954 let target = trait_ref
955 .substitution
956 .at(interner, 1)
957 .assert_ty_ref(interner)
958 .clone();
959
960 let mut place_in_environment = |goal| -> Goal<I> {
961 gb.forall(
962 &Binders::new(
963 binders.clone(),
964 (goal, trait_ref, &impl_datum.where_clauses),
965 ),
966 (),
967 |gb, _, (goal, trait_ref, where_clauses), ()| {
968 let interner = gb.interner();
969 gb.implies(
970 impl_wf_environment(interner, where_clauses, trait_ref),
971 |_| goal,
972 )
973 },
974 )
975 };
976
977 match (source.kind(interner), target.kind(interner)) {
978 (TyKind::Ref(s_m, _, source), TyKind::Ref(t_m, _, target))
979 | (TyKind::Ref(s_m, _, source), TyKind::Raw(t_m, target))
980 | (TyKind::Raw(s_m, source), TyKind::Raw(t_m, target)) => {
981 if (*s_m, *t_m) == (Mutability::Not, Mutability::Mut) {
982 return false;
983 }
984
985 let unsize_trait_id =
986 if let Some(id) = db.well_known_trait_id(WellKnownTrait::Unsize) {
987 id
988 } else {
989 return false;
990 };
991
992 let unsize_goal: Goal<I> = TraitRef {
994 trait_id: unsize_trait_id,
995 substitution: Substitution::from_iter(
996 interner,
997 [source.clone(), target.clone()].iter().cloned(),
998 ),
999 }
1000 .cast(interner);
1001
1002 let unsize_goal = place_in_environment(unsize_goal);
1004
1005 solver.has_unique_solution(db, &unsize_goal.into_closed_goal(interner))
1006 }
1007 (TyKind::Adt(source_id, subst_a), TyKind::Adt(target_id, subst_b)) => {
1008 let adt_datum = db.adt_datum(*source_id);
1009
1010 if source_id != target_id || adt_datum.kind != AdtKind::Struct {
1011 return false;
1012 }
1013
1014 let fields = adt_datum
1015 .binders
1016 .map_ref(|bound| &bound.variants.last().unwrap().fields)
1017 .cloned();
1018
1019 let (source_fields, target_fields) = (
1020 fields.clone().substitute(interner, subst_a),
1021 fields.substitute(interner, subst_b),
1022 );
1023
1024 let uneq_field_ids: Vec<usize> = (0..source_fields.len())
1026 .filter(|&i| {
1027 if let Some(adt_id) = source_fields[i].adt_id(interner) {
1029 if db.adt_datum(adt_id).flags.phantom_data {
1030 return false;
1031 }
1032 }
1033
1034 let eq_goal: Goal<I> = EqGoal {
1035 a: source_fields[i].clone().cast(interner),
1036 b: target_fields[i].clone().cast(interner),
1037 }
1038 .cast(interner);
1039
1040 let eq_goal = place_in_environment(eq_goal);
1042
1043 !solver.has_unique_solution(db, &eq_goal.into_closed_goal(interner))
1045 })
1046 .collect();
1047
1048 if uneq_field_ids.len() != 1 {
1049 return false;
1050 }
1051
1052 let field_id = uneq_field_ids[0];
1053
1054 let coerce_unsized_goal: Goal<I> = TraitRef {
1056 trait_id: trait_ref.trait_id,
1057 substitution: Substitution::from_iter(
1058 interner,
1059 [
1060 source_fields[field_id].clone(),
1061 target_fields[field_id].clone(),
1062 ]
1063 .iter()
1064 .cloned(),
1065 ),
1066 }
1067 .cast(interner);
1068
1069 let coerce_unsized_goal = place_in_environment(coerce_unsized_goal);
1071
1072 solver.has_unique_solution(db, &coerce_unsized_goal.into_closed_goal(interner))
1073 }
1074 _ => false,
1075 }
1076 }
1077
1078 fn dispatch_from_dyn_constraint<I: Interner>(
1092 solver: &mut dyn Solver<I>,
1093 db: &dyn RustIrDatabase<I>,
1094 impl_datum: &ImplDatum<I>,
1095 ) -> bool {
1096 let interner = db.interner();
1097 let mut gb = GoalBuilder::new(db);
1098
1099 let (binders, impl_datum) = impl_datum.binders.as_ref().into();
1100
1101 let trait_ref: &TraitRef<I> = &impl_datum.trait_ref;
1102
1103 let source = trait_ref.self_type_parameter(interner);
1105 let target = trait_ref
1106 .substitution
1107 .at(interner, 1)
1108 .assert_ty_ref(interner)
1109 .clone();
1110
1111 let mut place_in_environment = |goal| -> Goal<I> {
1112 gb.forall(
1113 &Binders::new(
1114 binders.clone(),
1115 (goal, trait_ref, &impl_datum.where_clauses),
1116 ),
1117 (),
1118 |gb, _, (goal, trait_ref, where_clauses), ()| {
1119 let interner = gb.interner();
1120 gb.implies(
1121 impl_wf_environment(interner, &where_clauses, &trait_ref),
1122 |_| goal,
1123 )
1124 },
1125 )
1126 };
1127
1128 match (source.kind(interner), target.kind(interner)) {
1129 (TyKind::Ref(s_m, _, _), TyKind::Ref(t_m, _, _))
1130 | (TyKind::Raw(s_m, _), TyKind::Raw(t_m, _))
1131 if s_m == t_m =>
1132 {
1133 true
1134 }
1135 (TyKind::Adt(source_id, subst_a), TyKind::Adt(target_id, subst_b)) => {
1136 let adt_datum = db.adt_datum(*source_id);
1137
1138 if source_id != target_id || adt_datum.kind != AdtKind::Struct {
1140 return false;
1141 }
1142
1143 let repr = db.adt_repr(*source_id);
1145 if repr.c || repr.packed {
1146 return false;
1147 }
1148
1149 let fields = adt_datum
1151 .binders
1152 .map_ref(|bound| &bound.variants.last().unwrap().fields)
1153 .cloned();
1154
1155 let (source_fields, target_fields) = (
1156 fields.clone().substitute(interner, subst_a),
1157 fields.substitute(interner, subst_b),
1158 );
1159
1160 let mut non_zst_fields: Vec<_> = source_fields
1161 .iter()
1162 .zip(target_fields.iter())
1163 .filter(|(sf, _)| match sf.adt_id(interner) {
1164 Some(adt) => !db.adt_size_align(adt).one_zst(),
1165 None => true,
1166 })
1167 .collect();
1168
1169 if non_zst_fields.len() != 1 {
1170 return false;
1171 }
1172
1173 let (field_src, field_tgt) = non_zst_fields.pop().unwrap();
1175
1176 let eq_goal: Goal<I> = EqGoal {
1178 a: field_src.clone().cast(interner),
1179 b: field_tgt.clone().cast(interner),
1180 }
1181 .cast(interner);
1182 let eq_goal = place_in_environment(eq_goal);
1183 if solver.has_unique_solution(db, &eq_goal.into_closed_goal(interner)) {
1184 return false;
1185 }
1186
1187 let field_dispatch_goal: Goal<I> = TraitRef {
1189 trait_id: trait_ref.trait_id,
1190 substitution: Substitution::from_iter(
1191 interner,
1192 [field_src.clone(), field_tgt.clone()].iter().cloned(),
1193 ),
1194 }
1195 .cast(interner);
1196 let field_dispatch_goal = place_in_environment(field_dispatch_goal);
1197 if !solver.has_unique_solution(db, &field_dispatch_goal.into_closed_goal(interner))
1198 {
1199 return false;
1200 }
1201
1202 true
1203 }
1204 _ => false,
1205 }
1206 }
1207}