@@ -30,75 +30,26 @@ where
30
30
) -> QueryResult<I> {
31
31
self.set_is_normalizes_to_goal();
32
32
debug_assert!(self.term_is_fully_unconstrained(goal));
33
- let normalize_result = self
34
- .probe(|&result| ProbeKind::TryNormalizeNonRigid { result })
35
- .enter(|this| this.normalize_at_least_one_step(goal));
36
-
37
- match normalize_result {
38
- Ok(res) => Ok(res),
39
- Err(NoSolution) => {
40
- self.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| {
41
- let Goal { param_env, predicate: NormalizesTo { alias, term } } = goal;
42
- this.add_rigid_constraints(param_env, alias)?;
43
- this.relate_rigid_alias_non_alias(param_env, alias, ty::Invariant, term)?;
44
- this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
45
- })
46
- }
47
- }
48
- }
49
-
50
- /// Register any obligations that are used to validate that an alias should be
51
- /// treated as rigid.
52
- ///
53
- /// An alias may be considered rigid if it fails normalization, but we also don't
54
- /// want to consider aliases that are not well-formed to be rigid simply because
55
- /// they fail normalization.
56
- ///
57
- /// For example, some `<T as Trait>::Assoc` where `T: Trait` does not hold, or an
58
- /// opaque type whose hidden type doesn't actually satisfy the opaque item bounds.
59
- fn add_rigid_constraints(
60
- &mut self,
61
- param_env: I::ParamEnv,
62
- rigid_alias: ty::AliasTerm<I>,
63
- ) -> Result<(), NoSolution> {
64
- let cx = self.cx();
65
- match rigid_alias.kind(cx) {
66
- // Projections are rigid only if their trait ref holds,
67
- // and the GAT where-clauses hold.
68
- ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
69
- let trait_ref = rigid_alias.trait_ref(cx);
70
- self.add_goal(GoalSource::AliasWellFormed, Goal::new(cx, param_env, trait_ref));
71
- Ok(())
72
- }
73
- ty::AliasTermKind::OpaqueTy => {
74
- if self.opaque_type_is_rigid(rigid_alias.def_id) {
75
- Ok(())
76
- } else {
77
- Err(NoSolution)
78
- }
79
- }
80
- // FIXME(generic_const_exprs): we would need to support generic consts here
81
- ty::AliasTermKind::UnevaluatedConst => Err(NoSolution),
82
- // Inherent and weak types are never rigid. This type must not be well-formed.
83
- ty::AliasTermKind::WeakTy | ty::AliasTermKind::InherentTy => Err(NoSolution),
84
- }
85
- }
86
-
87
- /// Normalize the given alias by at least one step. If the alias is rigid, this
88
- /// returns `NoSolution`.
89
- #[instrument(level = "trace", skip(self), ret)]
90
- fn normalize_at_least_one_step(&mut self, goal: Goal<I, NormalizesTo<I>>) -> QueryResult<I> {
91
33
let cx = self.cx();
92
34
match goal.predicate.alias.kind(cx) {
93
35
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
94
36
let candidates = self.assemble_and_evaluate_candidates(goal);
37
+ let trait_ref = goal.predicate.alias.trait_ref(cx);
95
38
let (_, proven_via) =
96
39
self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
97
- let trait_goal: Goal<I, ty::TraitPredicate<I>> =
98
- goal.with(cx, goal.predicate.alias.trait_ref(cx));
40
+ let trait_goal: Goal<I, ty::TraitPredicate<I>> = goal.with(cx, trait_ref);
99
41
ecx.compute_trait_goal(trait_goal)
100
42
})?;
101
- self.merge_candidates(proven_via, candidates)
43
+ self.merge_candidates(proven_via, candidates, |ecx| {
44
+ ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| {
45
+ this.structurally_instantiate_normalizes_to_term(
46
+ goal,
47
+ goal.predicate.alias,
48
+ );
49
+ this.add_goal(GoalSource::AliasWellFormed, goal.with(cx, trait_ref));
50
+ this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
51
+ })
52
+ })
102
53
}
103
54
ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal),
104
55
ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal),
@@ -120,6 +71,17 @@ where
120
71
self.eq(goal.param_env, goal.predicate.term, term)
121
72
.expect("expected goal term to be fully unconstrained");
122
73
}
74
+
75
+ /// Unlike `instantiate_normalizes_to_term` this instantiates the expected term
76
+ /// with a rigid alias. Using this is pretty much always wrong.
77
+ pub fn structurally_instantiate_normalizes_to_term(
78
+ &mut self,
79
+ goal: Goal<I, NormalizesTo<I>>,
80
+ term: ty::AliasTerm<I>,
81
+ ) {
82
+ self.relate_rigid_alias_non_alias(goal.param_env, term, ty::Invariant, goal.predicate.term)
83
+ .expect("expected goal term to be fully unconstrained");
84
+ }
123
85
}
124
86
125
87
impl<D, I> assembly::GoalKind<D> for NormalizesTo<I>
@@ -576,80 +538,92 @@ where
576
538
let cx = ecx.cx();
577
539
let metadata_def_id = cx.require_lang_item(TraitSolverLangItem::Metadata);
578
540
assert_eq!(metadata_def_id, goal.predicate.def_id());
579
- ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
580
- let metadata_ty = match goal.predicate.self_ty().kind() {
581
- ty::Bool
582
- | ty::Char
583
- | ty::Int(..)
584
- | ty::Uint(..)
585
- | ty::Float(..)
586
- | ty::Array(..)
587
- | ty::Pat(..)
588
- | ty::RawPtr(..)
589
- | ty::Ref(..)
590
- | ty::FnDef(..)
591
- | ty::FnPtr(..)
592
- | ty::Closure(..)
593
- | ty::CoroutineClosure(..)
594
- | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
595
- | ty::Coroutine(..)
596
- | ty::CoroutineWitness(..)
597
- | ty::Never
598
- | ty::Foreign(..)
599
- | ty::Dynamic(_, _, ty::DynStar) => Ty::new_unit(cx),
600
-
601
- ty::Error(e) => Ty::new_error(cx, e),
602
-
603
- ty::Str | ty::Slice(_) => Ty::new_usize(cx),
604
-
605
- ty::Dynamic(_, _, ty::Dyn) => {
606
- let dyn_metadata = cx.require_lang_item(TraitSolverLangItem::DynMetadata);
607
- cx.type_of(dyn_metadata)
608
- .instantiate(cx, &[I::GenericArg::from(goal.predicate.self_ty())])
609
- }
541
+ let metadata_ty = match goal.predicate.self_ty().kind() {
542
+ ty::Bool
543
+ | ty::Char
544
+ | ty::Int(..)
545
+ | ty::Uint(..)
546
+ | ty::Float(..)
547
+ | ty::Array(..)
548
+ | ty::Pat(..)
549
+ | ty::RawPtr(..)
550
+ | ty::Ref(..)
551
+ | ty::FnDef(..)
552
+ | ty::FnPtr(..)
553
+ | ty::Closure(..)
554
+ | ty::CoroutineClosure(..)
555
+ | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
556
+ | ty::Coroutine(..)
557
+ | ty::CoroutineWitness(..)
558
+ | ty::Never
559
+ | ty::Foreign(..)
560
+ | ty::Dynamic(_, _, ty::DynStar) => Ty::new_unit(cx),
610
561
611
- ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
612
- // This is the "fallback impl" for type parameters, unnormalizable projections
613
- // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`.
614
- // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't
615
- // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
616
- let sized_predicate = ty::TraitRef::new(
617
- cx,
618
- cx.require_lang_item(TraitSolverLangItem::Sized),
619
- [I::GenericArg::from(goal.predicate.self_ty())],
620
- );
621
- // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
622
- ecx.add_goal(GoalSource::Misc, goal.with(cx, sized_predicate));
623
- Ty::new_unit(cx)
624
- }
562
+ ty::Error(e) => Ty::new_error(cx, e),
625
563
626
- ty::Adt(def, args) if def.is_struct() => match def.struct_tail_ty(cx) {
627
- None => Ty::new_unit(cx),
628
- Some(tail_ty) => {
629
- Ty::new_projection(cx, metadata_def_id, [tail_ty.instantiate(cx, args)])
630
- }
631
- },
632
- ty::Adt(_, _) => Ty::new_unit(cx),
564
+ ty::Str | ty::Slice(_) => Ty::new_usize(cx),
633
565
634
- ty::Tuple(elements) => match elements.last() {
635
- None => Ty::new_unit(cx),
636
- Some(tail_ty) => Ty::new_projection(cx, metadata_def_id, [tail_ty]),
637
- },
566
+ ty::Dynamic(_, _, ty::Dyn) => {
567
+ let dyn_metadata = cx.require_lang_item(TraitSolverLangItem::DynMetadata);
568
+ cx.type_of(dyn_metadata)
569
+ .instantiate(cx, &[I::GenericArg::from(goal.predicate.self_ty())])
570
+ }
571
+
572
+ ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
573
+ // This is the "fallback impl" for type parameters, unnormalizable projections
574
+ // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`.
575
+ // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't
576
+ // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
577
+ let alias_bound_result =
578
+ ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
579
+ let sized_predicate = ty::TraitRef::new(
580
+ cx,
581
+ cx.require_lang_item(TraitSolverLangItem::Sized),
582
+ [I::GenericArg::from(goal.predicate.self_ty())],
583
+ );
584
+ ecx.add_goal(GoalSource::Misc, goal.with(cx, sized_predicate));
585
+ ecx.instantiate_normalizes_to_term(goal, Ty::new_unit(cx).into());
586
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
587
+ });
588
+ // In case the dummy alias-bound candidate does not apply, we instead treat this projection
589
+ // as rigid.
590
+ return alias_bound_result.or_else(|NoSolution| {
591
+ ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|this| {
592
+ this.structurally_instantiate_normalizes_to_term(
593
+ goal,
594
+ goal.predicate.alias,
595
+ );
596
+ this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
597
+ })
598
+ });
599
+ }
638
600
639
- ty::UnsafeBinder(_) => {
640
- // FIXME(unsafe_binder): Figure out how to handle pointee for unsafe binders.
641
- todo!()
601
+ ty::Adt(def, args) if def.is_struct() => match def.struct_tail_ty(cx) {
602
+ None => Ty::new_unit(cx),
603
+ Some(tail_ty) => {
604
+ Ty::new_projection(cx, metadata_def_id, [tail_ty.instantiate(cx, args)])
642
605
}
606
+ },
607
+ ty::Adt(_, _) => Ty::new_unit(cx),
643
608
644
- ty::Infer(
645
- ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
646
- )
647
- | ty::Bound(..) => panic!(
648
- "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
649
- goal.predicate.self_ty()
650
- ),
651
- };
609
+ ty::Tuple(elements) => match elements.last() {
610
+ None => Ty::new_unit(cx),
611
+ Some(tail_ty) => Ty::new_projection(cx, metadata_def_id, [tail_ty]),
612
+ },
652
613
614
+ ty::UnsafeBinder(_) => {
615
+ // FIXME(unsafe_binder): Figure out how to handle pointee for unsafe binders.
616
+ todo!()
617
+ }
618
+
619
+ ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
620
+ | ty::Bound(..) => panic!(
621
+ "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
622
+ goal.predicate.self_ty()
623
+ ),
624
+ };
625
+
626
+ ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
653
627
ecx.instantiate_normalizes_to_term(goal, metadata_ty.into());
654
628
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
655
629
})
@@ -850,12 +824,14 @@ where
850
824
todo!("discr subgoal...")
851
825
}
852
826
853
- // We do not call `Ty::discriminant_ty` on alias, param, or placeholder
854
- // types, which return `<self_ty as DiscriminantKind>::Discriminant`
855
- // (or ICE in the case of placeholders). Projecting a type to itself
856
- // is never really productive.
827
+ // Given an alias, parameter, or placeholder we add an impl candidate normalizing to a rigid
828
+ // alias. In case there's a where-bound further constraining this alias it is preferred over
829
+ // this impl candidate anyways. It's still a bit scuffed.
857
830
ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
858
- return Err(NoSolution);
831
+ return ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
832
+ ecx.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
833
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
834
+ });
859
835
}
860
836
861
837
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
@@ -902,12 +878,14 @@ where
902
878
todo!()
903
879
}
904
880
905
- // We do not call `Ty::async_destructor_ty` on alias, param, or placeholder
906
- // types, which return `<self_ty as AsyncDestruct>::AsyncDestructor`
907
- // (or ICE in the case of placeholders). Projecting a type to itself
908
- // is never really productive.
881
+ // Given an alias, parameter, or placeholder we add an impl candidate normalizing to a rigid
882
+ // alias. In case there's a where-bound further constraining this alias it is preferred over
883
+ // this impl candidate anyways. It's still a bit scuffed.
909
884
ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
910
- return Err(NoSolution);
885
+ return ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
886
+ ecx.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
887
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
888
+ });
911
889
}
912
890
913
891
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
0 commit comments