Skip to content

Commit f672436

Browse files
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

+33-215
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-
}

0 commit comments

Comments
 (0)