Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9227ff2

Browse files
committedJul 5, 2023
Auto merge of #113329 - lcnr:probe_candidate, r=BoxyUwU
add `ecx.probe_candidate` Not yet changing the candidate source to an enum because that would be more involved, but this by itself should already be a significant improvement imo r? `@BoxyUwU`
2 parents b7bc6f8 + 795c2ef commit 9227ff2

File tree

5 files changed

+280
-298
lines changed

5 files changed

+280
-298
lines changed
 

‎compiler/rustc_trait_selection/src/solve/alias_relate.rs

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use super::{EvalCtxt, SolverMode};
22
use rustc_infer::traits::query::NoSolution;
3-
use rustc_middle::traits::solve::inspect::CandidateKind;
43
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
54
use rustc_middle::ty;
65

@@ -110,12 +109,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
110109
direction: ty::AliasRelationDirection,
111110
invert: Invert,
112111
) -> QueryResult<'tcx> {
113-
self.probe(|r| CandidateKind::Candidate { name: "normalizes-to".into(), result: *r }).enter(
114-
|ecx| {
115-
ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?;
116-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
117-
},
118-
)
112+
self.probe_candidate("normalizes-to").enter(|ecx| {
113+
ecx.normalizes_to_inner(param_env, alias, other, direction, invert)?;
114+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
115+
})
119116
}
120117

121118
fn normalizes_to_inner(
@@ -156,20 +153,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
156153
alias_rhs: ty::AliasTy<'tcx>,
157154
direction: ty::AliasRelationDirection,
158155
) -> QueryResult<'tcx> {
159-
self.probe(|r| CandidateKind::Candidate { name: "substs relate".into(), result: *r }).enter(
160-
|ecx| {
161-
match direction {
162-
ty::AliasRelationDirection::Equate => {
163-
ecx.eq(param_env, alias_lhs, alias_rhs)?;
164-
}
165-
ty::AliasRelationDirection::Subtype => {
166-
ecx.sub(param_env, alias_lhs, alias_rhs)?;
167-
}
156+
self.probe_candidate("substs relate").enter(|ecx| {
157+
match direction {
158+
ty::AliasRelationDirection::Equate => {
159+
ecx.eq(param_env, alias_lhs, alias_rhs)?;
160+
}
161+
ty::AliasRelationDirection::Subtype => {
162+
ecx.sub(param_env, alias_lhs, alias_rhs)?;
168163
}
164+
}
169165

170-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
171-
},
172-
)
166+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
167+
})
173168
}
174169

175170
fn assemble_bidirectional_normalizes_to_candidate(
@@ -179,23 +174,22 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
179174
rhs: ty::Term<'tcx>,
180175
direction: ty::AliasRelationDirection,
181176
) -> QueryResult<'tcx> {
182-
self.probe(|r| CandidateKind::Candidate { name: "bidir normalizes-to".into(), result: *r })
183-
.enter(|ecx| {
184-
ecx.normalizes_to_inner(
185-
param_env,
186-
lhs.to_alias_ty(ecx.tcx()).unwrap(),
187-
rhs,
188-
direction,
189-
Invert::No,
190-
)?;
191-
ecx.normalizes_to_inner(
192-
param_env,
193-
rhs.to_alias_ty(ecx.tcx()).unwrap(),
194-
lhs,
195-
direction,
196-
Invert::Yes,
197-
)?;
198-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
199-
})
177+
self.probe_candidate("bidir normalizes-to").enter(|ecx| {
178+
ecx.normalizes_to_inner(
179+
param_env,
180+
lhs.to_alias_ty(ecx.tcx()).unwrap(),
181+
rhs,
182+
direction,
183+
Invert::No,
184+
)?;
185+
ecx.normalizes_to_inner(
186+
param_env,
187+
rhs.to_alias_ty(ecx.tcx()).unwrap(),
188+
lhs,
189+
direction,
190+
Invert::Yes,
191+
)?;
192+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
193+
})
200194
}
201195
}

‎compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_infer::infer::{
99
use rustc_infer::traits::query::NoSolution;
1010
use rustc_infer::traits::ObligationCause;
1111
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
12-
use rustc_middle::traits::solve::inspect::{self, CandidateKind};
12+
use rustc_middle::traits::solve::inspect;
1313
use rustc_middle::traits::solve::{
1414
CanonicalInput, CanonicalResponse, Certainty, IsNormalizesToHack, MaybeCause,
1515
PredefinedOpaques, PredefinedOpaquesData, QueryResult,
@@ -895,25 +895,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
895895
if candidate_key.def_id != key.def_id {
896896
continue;
897897
}
898-
values.extend(
899-
self.probe(|r| CandidateKind::Candidate {
900-
name: "opaque type storage".into(),
901-
result: *r,
902-
})
903-
.enter(|ecx| {
904-
for (a, b) in std::iter::zip(candidate_key.substs, key.substs) {
905-
ecx.eq(param_env, a, b)?;
906-
}
907-
ecx.eq(param_env, candidate_ty, ty)?;
908-
ecx.add_item_bounds_for_hidden_type(
909-
candidate_key.def_id.to_def_id(),
910-
candidate_key.substs,
911-
param_env,
912-
candidate_ty,
913-
);
914-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
915-
}),
916-
);
898+
values.extend(self.probe_candidate("opaque type storage").enter(|ecx| {
899+
for (a, b) in std::iter::zip(candidate_key.substs, key.substs) {
900+
ecx.eq(param_env, a, b)?;
901+
}
902+
ecx.eq(param_env, candidate_ty, ty)?;
903+
ecx.add_item_bounds_for_hidden_type(
904+
candidate_key.def_id.to_def_id(),
905+
candidate_key.substs,
906+
param_env,
907+
candidate_ty,
908+
);
909+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
910+
}));
917911
}
918912
values
919913
}

‎compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::EvalCtxt;
2-
use rustc_middle::traits::solve::inspect;
2+
use rustc_middle::traits::solve::{inspect, QueryResult};
33
use std::marker::PhantomData;
44

55
pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
@@ -44,4 +44,24 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
4444
{
4545
ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
4646
}
47+
48+
pub(in crate::solve) fn probe_candidate(
49+
&mut self,
50+
name: &'static str,
51+
) -> ProbeCtxt<
52+
'_,
53+
'a,
54+
'tcx,
55+
impl FnOnce(&QueryResult<'tcx>) -> inspect::CandidateKind<'tcx>,
56+
QueryResult<'tcx>,
57+
> {
58+
ProbeCtxt {
59+
ecx: self,
60+
probe_kind: move |result: &QueryResult<'tcx>| inspect::CandidateKind::Candidate {
61+
name: name.to_string(),
62+
result: *result,
63+
},
64+
_result: PhantomData,
65+
}
66+
}
4767
}

‎compiler/rustc_trait_selection/src/solve/project_goals.rs

Lines changed: 84 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -112,23 +112,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
112112
) -> QueryResult<'tcx> {
113113
if let Some(projection_pred) = assumption.as_projection_clause() {
114114
if projection_pred.projection_def_id() == goal.predicate.def_id() {
115-
ecx.probe(|r| CandidateKind::Candidate { name: "assumption".into(), result: *r })
116-
.enter(|ecx| {
117-
let assumption_projection_pred =
118-
ecx.instantiate_binder_with_infer(projection_pred);
119-
ecx.eq(
120-
goal.param_env,
121-
goal.predicate.projection_ty,
122-
assumption_projection_pred.projection_ty,
123-
)?;
124-
ecx.eq(
125-
goal.param_env,
126-
goal.predicate.term,
127-
assumption_projection_pred.term,
128-
)
115+
ecx.probe_candidate("assumption").enter(|ecx| {
116+
let assumption_projection_pred =
117+
ecx.instantiate_binder_with_infer(projection_pred);
118+
ecx.eq(
119+
goal.param_env,
120+
goal.predicate.projection_ty,
121+
assumption_projection_pred.projection_ty,
122+
)?;
123+
ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
129124
.expect("expected goal term to be fully unconstrained");
130-
then(ecx)
131-
})
125+
then(ecx)
126+
})
132127
} else {
133128
Err(NoSolution)
134129
}
@@ -328,91 +323,89 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
328323
goal: Goal<'tcx, Self>,
329324
) -> QueryResult<'tcx> {
330325
let tcx = ecx.tcx();
331-
ecx.probe(|r| CandidateKind::Candidate { name: "builtin pointee".into(), result: *r })
332-
.enter(|ecx| {
333-
let metadata_ty = match goal.predicate.self_ty().kind() {
334-
ty::Bool
335-
| ty::Char
336-
| ty::Int(..)
337-
| ty::Uint(..)
338-
| ty::Float(..)
339-
| ty::Array(..)
340-
| ty::RawPtr(..)
341-
| ty::Ref(..)
342-
| ty::FnDef(..)
343-
| ty::FnPtr(..)
344-
| ty::Closure(..)
345-
| ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
346-
| ty::Generator(..)
347-
| ty::GeneratorWitness(..)
348-
| ty::GeneratorWitnessMIR(..)
349-
| ty::Never
350-
| ty::Foreign(..) => tcx.types.unit,
351-
352-
ty::Error(e) => tcx.ty_error(*e),
353-
354-
ty::Str | ty::Slice(_) => tcx.types.usize,
355-
356-
ty::Dynamic(_, _, _) => {
357-
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
358-
tcx.type_of(dyn_metadata)
359-
.subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
360-
}
361-
362-
ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
363-
// FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
364-
let sized_predicate = ty::TraitRef::from_lang_item(
365-
tcx,
366-
LangItem::Sized,
367-
DUMMY_SP,
368-
[ty::GenericArg::from(goal.predicate.self_ty())],
369-
);
370-
ecx.add_goal(goal.with(tcx, sized_predicate));
371-
tcx.types.unit
372-
}
326+
ecx.probe_candidate("builtin pointee").enter(|ecx| {
327+
let metadata_ty = match goal.predicate.self_ty().kind() {
328+
ty::Bool
329+
| ty::Char
330+
| ty::Int(..)
331+
| ty::Uint(..)
332+
| ty::Float(..)
333+
| ty::Array(..)
334+
| ty::RawPtr(..)
335+
| ty::Ref(..)
336+
| ty::FnDef(..)
337+
| ty::FnPtr(..)
338+
| ty::Closure(..)
339+
| ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
340+
| ty::Generator(..)
341+
| ty::GeneratorWitness(..)
342+
| ty::GeneratorWitnessMIR(..)
343+
| ty::Never
344+
| ty::Foreign(..) => tcx.types.unit,
345+
346+
ty::Error(e) => tcx.ty_error(*e),
347+
348+
ty::Str | ty::Slice(_) => tcx.types.usize,
349+
350+
ty::Dynamic(_, _, _) => {
351+
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
352+
tcx.type_of(dyn_metadata)
353+
.subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
354+
}
373355

374-
ty::Adt(def, substs) if def.is_struct() => {
375-
match def.non_enum_variant().fields.raw.last() {
376-
None => tcx.types.unit,
377-
Some(field_def) => {
378-
let self_ty = field_def.ty(tcx, substs);
379-
ecx.add_goal(goal.with(
380-
tcx,
381-
ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
382-
));
383-
return ecx.evaluate_added_goals_and_make_canonical_response(
384-
Certainty::Yes,
385-
);
386-
}
387-
}
388-
}
389-
ty::Adt(_, _) => tcx.types.unit,
356+
ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
357+
// FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
358+
let sized_predicate = ty::TraitRef::from_lang_item(
359+
tcx,
360+
LangItem::Sized,
361+
DUMMY_SP,
362+
[ty::GenericArg::from(goal.predicate.self_ty())],
363+
);
364+
ecx.add_goal(goal.with(tcx, sized_predicate));
365+
tcx.types.unit
366+
}
390367

391-
ty::Tuple(elements) => match elements.last() {
368+
ty::Adt(def, substs) if def.is_struct() => {
369+
match def.non_enum_variant().fields.raw.last() {
392370
None => tcx.types.unit,
393-
Some(&self_ty) => {
371+
Some(field_def) => {
372+
let self_ty = field_def.ty(tcx, substs);
394373
ecx.add_goal(goal.with(
395374
tcx,
396375
ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
397376
));
398377
return ecx
399378
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
400379
}
401-
},
402-
403-
ty::Infer(
404-
ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
405-
)
406-
| ty::Bound(..) => bug!(
407-
"unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
408-
goal.predicate.self_ty()
409-
),
410-
};
380+
}
381+
}
382+
ty::Adt(_, _) => tcx.types.unit,
411383

412-
ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())
413-
.expect("expected goal term to be fully unconstrained");
414-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
415-
})
384+
ty::Tuple(elements) => match elements.last() {
385+
None => tcx.types.unit,
386+
Some(&self_ty) => {
387+
ecx.add_goal(goal.with(
388+
tcx,
389+
ty::Binder::dummy(goal.predicate.with_self_ty(tcx, self_ty)),
390+
));
391+
return ecx
392+
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
393+
}
394+
},
395+
396+
ty::Infer(
397+
ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
398+
)
399+
| ty::Bound(..) => bug!(
400+
"unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
401+
goal.predicate.self_ty()
402+
),
403+
};
404+
405+
ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())
406+
.expect("expected goal term to be fully unconstrained");
407+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
408+
})
416409
}
417410

418411
fn consider_builtin_future_candidate(
@@ -547,11 +540,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
547540
),
548541
};
549542

550-
ecx.probe(|r| CandidateKind::Candidate {
551-
name: "builtin discriminant kind".into(),
552-
result: *r,
553-
})
554-
.enter(|ecx| {
543+
ecx.probe_candidate("builtin discriminant kind").enter(|ecx| {
555544
ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into())
556545
.expect("expected goal term to be fully unconstrained");
557546
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)

‎compiler/rustc_trait_selection/src/solve/trait_goals.rs

Lines changed: 130 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use rustc_hir::def_id::DefId;
66
use rustc_hir::{LangItem, Movability};
77
use rustc_infer::traits::query::NoSolution;
88
use rustc_infer::traits::util::supertraits;
9-
use rustc_middle::traits::solve::inspect::CandidateKind;
109
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
1110
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
1211
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
@@ -62,7 +61,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
6261
},
6362
};
6463

65-
ecx.probe(|r| CandidateKind::Candidate { name: "impl".into(), result: *r }).enter(|ecx| {
64+
ecx.probe_candidate("impl").enter(|ecx| {
6665
let impl_substs = ecx.fresh_substs_for_item(impl_def_id);
6766
let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs);
6867

@@ -90,16 +89,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
9089
&& trait_clause.polarity() == goal.predicate.polarity
9190
{
9291
// FIXME: Constness
93-
ecx.probe(|r| CandidateKind::Candidate { name: "assumption".into(), result: *r })
94-
.enter(|ecx| {
95-
let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
96-
ecx.eq(
97-
goal.param_env,
98-
goal.predicate.trait_ref,
99-
assumption_trait_pred.trait_ref,
100-
)?;
101-
then(ecx)
102-
})
92+
ecx.probe_candidate("assumption").enter(|ecx| {
93+
let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
94+
ecx.eq(
95+
goal.param_env,
96+
goal.predicate.trait_ref,
97+
assumption_trait_pred.trait_ref,
98+
)?;
99+
then(ecx)
100+
})
103101
} else {
104102
Err(NoSolution)
105103
}
@@ -136,15 +134,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
136134

137135
let tcx = ecx.tcx();
138136

139-
ecx.probe(|r| CandidateKind::Candidate { name: "trait alias".into(), result: *r }).enter(
140-
|ecx| {
141-
let nested_obligations = tcx
142-
.predicates_of(goal.predicate.def_id())
143-
.instantiate(tcx, goal.predicate.trait_ref.substs);
144-
ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)));
145-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
146-
},
147-
)
137+
ecx.probe_candidate("trait alias").enter(|ecx| {
138+
let nested_obligations = tcx
139+
.predicates_of(goal.predicate.def_id())
140+
.instantiate(tcx, goal.predicate.trait_ref.substs);
141+
ecx.add_goals(nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)));
142+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
143+
})
148144
}
149145

150146
fn consider_builtin_sized_candidate(
@@ -350,115 +346,109 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
350346
if b_ty.is_ty_var() {
351347
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
352348
}
353-
ecx.probe(|r| CandidateKind::Candidate { name: "builtin unsize".into(), result: *r }).enter(
354-
|ecx| {
355-
match (a_ty.kind(), b_ty.kind()) {
356-
// Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
357-
(&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => {
358-
// Dyn upcasting is handled separately, since due to upcasting,
359-
// when there are two supertraits that differ by substs, we
360-
// may return more than one query response.
361-
Err(NoSolution)
349+
ecx.probe_candidate("builtin unsize").enter(|ecx| {
350+
match (a_ty.kind(), b_ty.kind()) {
351+
// Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`
352+
(&ty::Dynamic(_, _, ty::Dyn), &ty::Dynamic(_, _, ty::Dyn)) => {
353+
// Dyn upcasting is handled separately, since due to upcasting,
354+
// when there are two supertraits that differ by substs, we
355+
// may return more than one query response.
356+
Err(NoSolution)
357+
}
358+
// `T` -> `dyn Trait` unsizing
359+
(_, &ty::Dynamic(data, region, ty::Dyn)) => {
360+
// Can only unsize to an object-safe type
361+
if data
362+
.principal_def_id()
363+
.is_some_and(|def_id| !tcx.check_is_object_safe(def_id))
364+
{
365+
return Err(NoSolution);
362366
}
363-
// `T` -> `dyn Trait` unsizing
364-
(_, &ty::Dynamic(data, region, ty::Dyn)) => {
365-
// Can only unsize to an object-safe type
366-
if data
367-
.principal_def_id()
368-
.is_some_and(|def_id| !tcx.check_is_object_safe(def_id))
369-
{
370-
return Err(NoSolution);
371-
}
372-
373-
let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
367+
368+
let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
374369
return Err(NoSolution);
375370
};
376-
// Check that the type implements all of the predicates of the def-id.
377-
// (i.e. the principal, all of the associated types match, and any auto traits)
378-
ecx.add_goals(
379-
data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
380-
);
381-
// The type must be Sized to be unsized.
382-
ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])));
383-
// The type must outlive the lifetime of the `dyn` we're unsizing into.
384-
ecx.add_goal(
385-
goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))),
386-
);
387-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
388-
}
389-
// `[T; n]` -> `[T]` unsizing
390-
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
391-
// We just require that the element type stays the same
392-
ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
393-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
394-
}
395-
// Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
396-
(&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
397-
if a_def.is_struct() && a_def.did() == b_def.did() =>
398-
{
399-
let unsizing_params = tcx.unsizing_params_for_adt(a_def.did());
400-
// We must be unsizing some type parameters. This also implies
401-
// that the struct has a tail field.
402-
if unsizing_params.is_empty() {
403-
return Err(NoSolution);
404-
}
405-
406-
let tail_field = a_def
407-
.non_enum_variant()
408-
.fields
409-
.raw
410-
.last()
411-
.expect("expected unsized ADT to have a tail field");
412-
let tail_field_ty = tcx.type_of(tail_field.did);
413-
414-
let a_tail_ty = tail_field_ty.subst(tcx, a_substs);
415-
let b_tail_ty = tail_field_ty.subst(tcx, b_substs);
416-
417-
// Substitute just the unsizing params from B into A. The type after
418-
// this substitution must be equal to B. This is so we don't unsize
419-
// unrelated type parameters.
420-
let new_a_substs =
421-
tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| {
422-
if unsizing_params.contains(i as u32) { b_substs[i] } else { a }
423-
}));
424-
let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs);
425-
426-
// Finally, we require that `TailA: Unsize<TailB>` for the tail field
427-
// types.
428-
ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
429-
ecx.add_goal(goal.with(
430-
tcx,
431-
ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
432-
));
433-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
434-
}
435-
// Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
436-
(&ty::Tuple(a_tys), &ty::Tuple(b_tys))
437-
if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
438-
{
439-
let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
440-
let b_last_ty = b_tys.last().unwrap();
441-
442-
// Substitute just the tail field of B., and require that they're equal.
443-
let unsized_a_ty =
444-
tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied());
445-
ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
446-
447-
// Similar to ADTs, require that the rest of the fields are equal.
448-
ecx.add_goal(goal.with(
449-
tcx,
450-
ty::TraitRef::new(
451-
tcx,
452-
goal.predicate.def_id(),
453-
[*a_last_ty, *b_last_ty],
454-
),
455-
));
456-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
371+
// Check that the type implements all of the predicates of the def-id.
372+
// (i.e. the principal, all of the associated types match, and any auto traits)
373+
ecx.add_goals(
374+
data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
375+
);
376+
// The type must be Sized to be unsized.
377+
ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])));
378+
// The type must outlive the lifetime of the `dyn` we're unsizing into.
379+
ecx.add_goal(
380+
goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))),
381+
);
382+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
383+
}
384+
// `[T; n]` -> `[T]` unsizing
385+
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
386+
// We just require that the element type stays the same
387+
ecx.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
388+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
389+
}
390+
// Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
391+
(&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
392+
if a_def.is_struct() && a_def.did() == b_def.did() =>
393+
{
394+
let unsizing_params = tcx.unsizing_params_for_adt(a_def.did());
395+
// We must be unsizing some type parameters. This also implies
396+
// that the struct has a tail field.
397+
if unsizing_params.is_empty() {
398+
return Err(NoSolution);
457399
}
458-
_ => Err(NoSolution),
400+
401+
let tail_field = a_def
402+
.non_enum_variant()
403+
.fields
404+
.raw
405+
.last()
406+
.expect("expected unsized ADT to have a tail field");
407+
let tail_field_ty = tcx.type_of(tail_field.did);
408+
409+
let a_tail_ty = tail_field_ty.subst(tcx, a_substs);
410+
let b_tail_ty = tail_field_ty.subst(tcx, b_substs);
411+
412+
// Substitute just the unsizing params from B into A. The type after
413+
// this substitution must be equal to B. This is so we don't unsize
414+
// unrelated type parameters.
415+
let new_a_substs =
416+
tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| {
417+
if unsizing_params.contains(i as u32) { b_substs[i] } else { a }
418+
}));
419+
let unsized_a_ty = tcx.mk_adt(a_def, new_a_substs);
420+
421+
// Finally, we require that `TailA: Unsize<TailB>` for the tail field
422+
// types.
423+
ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
424+
ecx.add_goal(goal.with(
425+
tcx,
426+
ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
427+
));
428+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
459429
}
460-
},
461-
)
430+
// Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
431+
(&ty::Tuple(a_tys), &ty::Tuple(b_tys))
432+
if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
433+
{
434+
let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
435+
let b_last_ty = b_tys.last().unwrap();
436+
437+
// Substitute just the tail field of B., and require that they're equal.
438+
let unsized_a_ty =
439+
tcx.mk_tup_from_iter(a_rest_tys.iter().chain([b_last_ty]).copied());
440+
ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
441+
442+
// Similar to ADTs, require that the rest of the fields are equal.
443+
ecx.add_goal(goal.with(
444+
tcx,
445+
ty::TraitRef::new(tcx, goal.predicate.def_id(), [*a_last_ty, *b_last_ty]),
446+
));
447+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
448+
}
449+
_ => Err(NoSolution),
450+
}
451+
})
462452
}
463453

464454
fn consider_builtin_dyn_upcast_candidates(
@@ -488,11 +478,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
488478
}
489479

490480
let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
491-
ecx.probe(|r| CandidateKind::Candidate {
492-
name: "upcast dyn to principle".into(),
493-
result: *r,
494-
})
495-
.enter(|ecx| -> Result<_, NoSolution> {
481+
ecx.probe_candidate("upcast dyn to principle").enter(|ecx| -> Result<_, NoSolution> {
496482
// Require that all of the trait predicates from A match B, except for
497483
// the auto traits. We do this by constructing a new A type with B's
498484
// auto traits, and equating these types.
@@ -714,21 +700,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
714700
goal: Goal<'tcx, TraitPredicate<'tcx>>,
715701
constituent_tys: impl Fn(&EvalCtxt<'_, 'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
716702
) -> QueryResult<'tcx> {
717-
self.probe(|r| CandidateKind::Candidate { name: "constituent tys".into(), result: *r })
718-
.enter(|ecx| {
719-
ecx.add_goals(
720-
constituent_tys(ecx, goal.predicate.self_ty())?
721-
.into_iter()
722-
.map(|ty| {
723-
goal.with(
724-
ecx.tcx(),
725-
ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)),
726-
)
727-
})
728-
.collect::<Vec<_>>(),
729-
);
730-
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
731-
})
703+
self.probe_candidate("constituent tys").enter(|ecx| {
704+
ecx.add_goals(
705+
constituent_tys(ecx, goal.predicate.self_ty())?
706+
.into_iter()
707+
.map(|ty| {
708+
goal.with(
709+
ecx.tcx(),
710+
ty::Binder::dummy(goal.predicate.with_self_ty(ecx.tcx(), ty)),
711+
)
712+
})
713+
.collect::<Vec<_>>(),
714+
);
715+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
716+
})
732717
}
733718

734719
#[instrument(level = "debug", skip(self))]

0 commit comments

Comments
 (0)
Please sign in to comment.