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 f672436

Browse files
committedJan 18, 2023
Handle structural traits more gracefully
1 parent 34127c5 commit f672436

File tree

2 files changed

+212
-215
lines changed

2 files changed

+212
-215
lines changed
 

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

Lines changed: 33 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ use super::assembly::{self, Candidate, CandidateSource};
66
use super::infcx_ext::InferCtxtExt;
77
use super::{EvalCtxt, Goal, QueryResult};
88
use rustc_hir::def_id::DefId;
9-
use rustc_hir::{Movability, Mutability};
109
use rustc_infer::infer::InferCtxt;
1110
use rustc_infer::traits::query::NoSolution;
1211
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
1312
use rustc_middle::ty::TraitPredicate;
1413
use rustc_middle::ty::{self, Ty, TyCtxt};
1514
use rustc_span::DUMMY_SP;
1615

16+
mod structural_traits;
17+
1718
impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
1819
fn self_ty(self) -> Ty<'tcx> {
1920
self.self_ty()
@@ -85,11 +86,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
8586
ecx: &mut EvalCtxt<'_, 'tcx>,
8687
goal: Goal<'tcx, Self>,
8788
) -> QueryResult<'tcx> {
88-
ecx.infcx.probe(|_| {
89-
let constituent_tys =
90-
instantiate_constituent_tys_for_auto_trait(ecx.infcx, goal.predicate.self_ty())?;
91-
ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys)
92-
})
89+
ecx.probe_and_evaluate_goal_for_constituent_tys(
90+
goal,
91+
structural_traits::instantiate_constituent_tys_for_auto_trait,
92+
)
9393
}
9494

9595
fn consider_trait_alias_candidate(
@@ -112,44 +112,46 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
112112
ecx: &mut EvalCtxt<'_, 'tcx>,
113113
goal: Goal<'tcx, Self>,
114114
) -> QueryResult<'tcx> {
115-
ecx.infcx.probe(|_| {
116-
let constituent_tys =
117-
instantiate_constituent_tys_for_sized_trait(ecx.infcx, goal.predicate.self_ty())?;
118-
ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys)
119-
})
115+
ecx.probe_and_evaluate_goal_for_constituent_tys(
116+
goal,
117+
structural_traits::instantiate_constituent_tys_for_sized_trait,
118+
)
120119
}
121120

122121
fn consider_builtin_copy_clone_candidate(
123122
ecx: &mut EvalCtxt<'_, 'tcx>,
124123
goal: Goal<'tcx, Self>,
125124
) -> QueryResult<'tcx> {
126-
ecx.infcx.probe(|_| {
127-
let constituent_tys = instantiate_constituent_tys_for_copy_clone_trait(
128-
ecx.infcx,
129-
goal.predicate.self_ty(),
130-
)?;
131-
ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys)
132-
})
125+
ecx.probe_and_evaluate_goal_for_constituent_tys(
126+
goal,
127+
structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
128+
)
133129
}
134130
}
135131

136132
impl<'tcx> EvalCtxt<'_, 'tcx> {
137-
fn evaluate_goal_for_constituent_tys_and_make_canonical_response(
133+
/// Convenience function for traits that are structural, i.e. that only
134+
/// have nested subgoals that only change the self type. Unlike other
135+
/// evaluate-like helpers, this does a probe, so it doesn't need to be
136+
/// wrapped in one.
137+
fn probe_and_evaluate_goal_for_constituent_tys(
138138
&mut self,
139139
goal: Goal<'tcx, TraitPredicate<'tcx>>,
140-
constituent_tys: Vec<Ty<'tcx>>,
140+
constituent_tys: impl Fn(&InferCtxt<'tcx>, Ty<'tcx>) -> Result<Vec<Ty<'tcx>>, NoSolution>,
141141
) -> QueryResult<'tcx> {
142-
self.evaluate_all_and_make_canonical_response(
143-
constituent_tys
144-
.into_iter()
145-
.map(|ty| {
146-
goal.with(
147-
self.tcx(),
148-
ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)),
149-
)
150-
})
151-
.collect(),
152-
)
142+
self.infcx.probe(|_| {
143+
self.evaluate_all_and_make_canonical_response(
144+
constituent_tys(self.infcx, goal.predicate.self_ty())?
145+
.into_iter()
146+
.map(|ty| {
147+
goal.with(
148+
self.tcx(),
149+
ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)),
150+
)
151+
})
152+
.collect(),
153+
)
154+
})
153155
}
154156

155157
pub(super) fn compute_trait_goal(
@@ -227,187 +229,3 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
227229
candidate
228230
}
229231
}
230-
231-
// Calculates the constituent types of a type for `auto trait` purposes.
232-
//
233-
// For types with an "existential" binder, i.e. generator witnesses, we also
234-
// instantiate the binder with placeholders eagerly.
235-
fn instantiate_constituent_tys_for_auto_trait<'tcx>(
236-
infcx: &InferCtxt<'tcx>,
237-
ty: Ty<'tcx>,
238-
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
239-
let tcx = infcx.tcx;
240-
match *ty.kind() {
241-
ty::Uint(_)
242-
| ty::Int(_)
243-
| ty::Bool
244-
| ty::Float(_)
245-
| ty::FnDef(..)
246-
| ty::FnPtr(_)
247-
| ty::Str
248-
| ty::Error(_)
249-
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
250-
| ty::Never
251-
| ty::Char => Ok(vec![]),
252-
253-
ty::Placeholder(..)
254-
| ty::Dynamic(..)
255-
| ty::Param(..)
256-
| ty::Foreign(..)
257-
| ty::Alias(ty::Projection, ..)
258-
| ty::Bound(..)
259-
| ty::Infer(ty::TyVar(_)) => {
260-
// FIXME: Do we need to mark anything as ambiguous here? Yeah?
261-
Err(NoSolution)
262-
}
263-
264-
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
265-
266-
ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
267-
Ok(vec![element_ty])
268-
}
269-
270-
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
271-
272-
ty::Tuple(ref tys) => {
273-
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
274-
Ok(tys.iter().collect())
275-
}
276-
277-
ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
278-
279-
ty::Generator(_, ref substs, _) => {
280-
let generator_substs = substs.as_generator();
281-
Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()])
282-
}
283-
284-
ty::GeneratorWitness(types) => {
285-
Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
286-
}
287-
288-
// For `PhantomData<T>`, we pass `T`.
289-
ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]),
290-
291-
ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()),
292-
293-
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
294-
// We can resolve the `impl Trait` to its concrete type,
295-
// which enforces a DAG between the functions requiring
296-
// the auto trait bounds in question.
297-
Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)])
298-
}
299-
}
300-
}
301-
302-
fn instantiate_constituent_tys_for_sized_trait<'tcx>(
303-
infcx: &InferCtxt<'tcx>,
304-
ty: Ty<'tcx>,
305-
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
306-
match *ty.kind() {
307-
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
308-
| ty::Uint(_)
309-
| ty::Int(_)
310-
| ty::Bool
311-
| ty::Float(_)
312-
| ty::FnDef(..)
313-
| ty::FnPtr(_)
314-
| ty::RawPtr(..)
315-
| ty::Char
316-
| ty::Ref(..)
317-
| ty::Generator(..)
318-
| ty::GeneratorWitness(..)
319-
| ty::Array(..)
320-
| ty::Closure(..)
321-
| ty::Never
322-
| ty::Dynamic(_, _, ty::DynStar)
323-
| ty::Error(_) => Ok(vec![]),
324-
325-
ty::Str
326-
| ty::Slice(_)
327-
| ty::Dynamic(..)
328-
| ty::Foreign(..)
329-
| ty::Alias(..)
330-
| ty::Param(_) => Err(NoSolution),
331-
332-
ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
333-
334-
ty::Placeholder(..)
335-
| ty::Bound(..)
336-
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
337-
338-
ty::Tuple(tys) => Ok(tys.to_vec()),
339-
340-
ty::Adt(def, substs) => {
341-
let sized_crit = def.sized_constraint(infcx.tcx);
342-
Ok(sized_crit
343-
.0
344-
.iter()
345-
.map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs))
346-
.collect())
347-
}
348-
}
349-
}
350-
351-
fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
352-
infcx: &InferCtxt<'tcx>,
353-
ty: Ty<'tcx>,
354-
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
355-
match *ty.kind() {
356-
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
357-
| ty::FnDef(..)
358-
| ty::FnPtr(_)
359-
| ty::Error(_) => Ok(vec![]),
360-
361-
// Implementations are provided in core
362-
ty::Uint(_)
363-
| ty::Int(_)
364-
| ty::Bool
365-
| ty::Float(_)
366-
| ty::Char
367-
| ty::RawPtr(..)
368-
| ty::Never
369-
| ty::Ref(_, _, Mutability::Not)
370-
| ty::Array(..) => Err(NoSolution),
371-
372-
ty::Dynamic(..)
373-
| ty::Str
374-
| ty::Slice(_)
375-
| ty::Generator(_, _, Movability::Static)
376-
| ty::Foreign(..)
377-
| ty::Ref(_, _, Mutability::Mut)
378-
| ty::Adt(_, _)
379-
| ty::Alias(_, _)
380-
| ty::Param(_) => Err(NoSolution),
381-
382-
ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
383-
384-
ty::Placeholder(..)
385-
| ty::Bound(..)
386-
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
387-
388-
ty::Tuple(tys) => Ok(tys.to_vec()),
389-
390-
ty::Closure(_, substs) => match *substs.as_closure().tupled_upvars_ty().kind() {
391-
ty::Tuple(tys) => Ok(tys.to_vec()),
392-
ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
393-
_ => bug!(),
394-
},
395-
396-
ty::Generator(_, substs, Movability::Movable) => {
397-
if infcx.tcx.features().generator_clone {
398-
let generator = substs.as_generator();
399-
match *generator.tupled_upvars_ty().kind() {
400-
ty::Tuple(tys) => Ok(tys.iter().chain([generator.witness()]).collect()),
401-
ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
402-
_ => bug!(),
403-
}
404-
} else {
405-
Err(NoSolution)
406-
}
407-
}
408-
409-
ty::GeneratorWitness(types) => {
410-
Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
411-
}
412-
}
413-
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
use rustc_hir::{Movability, Mutability};
2+
use rustc_infer::{infer::InferCtxt, traits::query::NoSolution};
3+
use rustc_middle::ty::{self, Ty};
4+
5+
// Calculates the constituent types of a type for `auto trait` purposes.
6+
//
7+
// For types with an "existential" binder, i.e. generator witnesses, we also
8+
// instantiate the binder with placeholders eagerly.
9+
pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
10+
infcx: &InferCtxt<'tcx>,
11+
ty: Ty<'tcx>,
12+
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
13+
let tcx = infcx.tcx;
14+
match *ty.kind() {
15+
ty::Uint(_)
16+
| ty::Int(_)
17+
| ty::Bool
18+
| ty::Float(_)
19+
| ty::FnDef(..)
20+
| ty::FnPtr(_)
21+
| ty::Str
22+
| ty::Error(_)
23+
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
24+
| ty::Never
25+
| ty::Char => Ok(vec![]),
26+
27+
ty::Placeholder(..)
28+
| ty::Dynamic(..)
29+
| ty::Param(..)
30+
| ty::Foreign(..)
31+
| ty::Alias(ty::Projection, ..)
32+
| ty::Bound(..)
33+
| ty::Infer(ty::TyVar(_)) => {
34+
// FIXME: Do we need to mark anything as ambiguous here? Yeah?
35+
Err(NoSolution)
36+
}
37+
38+
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
39+
40+
ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
41+
Ok(vec![element_ty])
42+
}
43+
44+
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
45+
46+
ty::Tuple(ref tys) => {
47+
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
48+
Ok(tys.iter().collect())
49+
}
50+
51+
ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
52+
53+
ty::Generator(_, ref substs, _) => {
54+
let generator_substs = substs.as_generator();
55+
Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()])
56+
}
57+
58+
ty::GeneratorWitness(types) => {
59+
Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
60+
}
61+
62+
// For `PhantomData<T>`, we pass `T`.
63+
ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]),
64+
65+
ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()),
66+
67+
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
68+
// We can resolve the `impl Trait` to its concrete type,
69+
// which enforces a DAG between the functions requiring
70+
// the auto trait bounds in question.
71+
Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)])
72+
}
73+
}
74+
}
75+
76+
pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
77+
infcx: &InferCtxt<'tcx>,
78+
ty: Ty<'tcx>,
79+
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
80+
match *ty.kind() {
81+
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
82+
| ty::Uint(_)
83+
| ty::Int(_)
84+
| ty::Bool
85+
| ty::Float(_)
86+
| ty::FnDef(..)
87+
| ty::FnPtr(_)
88+
| ty::RawPtr(..)
89+
| ty::Char
90+
| ty::Ref(..)
91+
| ty::Generator(..)
92+
| ty::GeneratorWitness(..)
93+
| ty::Array(..)
94+
| ty::Closure(..)
95+
| ty::Never
96+
| ty::Dynamic(_, _, ty::DynStar)
97+
| ty::Error(_) => Ok(vec![]),
98+
99+
ty::Str
100+
| ty::Slice(_)
101+
| ty::Dynamic(..)
102+
| ty::Foreign(..)
103+
| ty::Alias(..)
104+
| ty::Param(_) => Err(NoSolution),
105+
106+
ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
107+
108+
ty::Placeholder(..)
109+
| ty::Bound(..)
110+
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
111+
112+
ty::Tuple(tys) => Ok(tys.to_vec()),
113+
114+
ty::Adt(def, substs) => {
115+
let sized_crit = def.sized_constraint(infcx.tcx);
116+
Ok(sized_crit
117+
.0
118+
.iter()
119+
.map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs))
120+
.collect())
121+
}
122+
}
123+
}
124+
125+
pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
126+
infcx: &InferCtxt<'tcx>,
127+
ty: Ty<'tcx>,
128+
) -> Result<Vec<Ty<'tcx>>, NoSolution> {
129+
match *ty.kind() {
130+
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
131+
| ty::FnDef(..)
132+
| ty::FnPtr(_)
133+
| ty::Error(_) => Ok(vec![]),
134+
135+
// Implementations are provided in core
136+
ty::Uint(_)
137+
| ty::Int(_)
138+
| ty::Bool
139+
| ty::Float(_)
140+
| ty::Char
141+
| ty::RawPtr(..)
142+
| ty::Never
143+
| ty::Ref(_, _, Mutability::Not)
144+
| ty::Array(..) => Err(NoSolution),
145+
146+
ty::Dynamic(..)
147+
| ty::Str
148+
| ty::Slice(_)
149+
| ty::Generator(_, _, Movability::Static)
150+
| ty::Foreign(..)
151+
| ty::Ref(_, _, Mutability::Mut)
152+
| ty::Adt(_, _)
153+
| ty::Alias(_, _)
154+
| ty::Param(_) => Err(NoSolution),
155+
156+
ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"),
157+
158+
ty::Placeholder(..)
159+
| ty::Bound(..)
160+
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
161+
162+
ty::Tuple(tys) => Ok(tys.to_vec()),
163+
164+
ty::Closure(_, substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
165+
166+
ty::Generator(_, substs, Movability::Movable) => {
167+
if infcx.tcx.features().generator_clone {
168+
let generator = substs.as_generator();
169+
Ok(vec![generator.tupled_upvars_ty(), generator.witness()])
170+
} else {
171+
Err(NoSolution)
172+
}
173+
}
174+
175+
ty::GeneratorWitness(types) => {
176+
Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
177+
}
178+
}
179+
}

0 commit comments

Comments
 (0)
Please sign in to comment.