Skip to content

Commit 779a435

Browse files
Refactor traits that have constituent components
1 parent 3d99330 commit 779a435

File tree

1 file changed

+218
-48
lines changed

1 file changed

+218
-48
lines changed

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+218-48
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ use std::iter;
55
use crate::traits::TupleArgumentsFlag;
66

77
use super::assembly::{self, AssemblyCtxt};
8-
use super::{CanonicalGoal, Certainty, EvalCtxt, Goal, QueryResult};
8+
use super::{CanonicalGoal, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
9+
910
use rustc_hir::def_id::DefId;
10-
use rustc_hir::Unsafety;
11+
use rustc_hir::{Movability, Mutability, Unsafety};
1112
use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
1213
use rustc_infer::traits::query::NoSolution;
1314
use rustc_infer::traits::util::supertraits;
@@ -225,20 +226,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
225226
) {
226227
// FIXME: We need to give auto trait candidates less precedence than impl candidates?
227228
acx.infcx.probe(|_| {
228-
let Ok(constituent_tys) =
229-
instantiate_constituent_tys_for_auto_trait(acx.infcx, goal.predicate.self_ty()) else { return };
230-
let nested_goals = constituent_tys
231-
.into_iter()
232-
.map(|ty| {
233-
Goal::new(
234-
acx.cx.tcx,
235-
goal.param_env,
236-
ty::Binder::dummy(goal.predicate.with_self_ty(acx.cx.tcx, ty)),
237-
)
238-
})
239-
.collect();
240-
let Ok(certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return };
241-
acx.try_insert_candidate(CandidateSource::AutoImpl, certainty);
229+
let components =
230+
instantiate_constituent_tys_for_auto_trait(acx.infcx, goal.predicate.self_ty());
231+
evaluate_goal_for_components(acx, goal, components, CandidateSource::AutoImpl);
242232
})
243233
}
244234

@@ -284,36 +274,51 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
284274
let self_ty = goal.predicate.self_ty();
285275

286276
if Some(trait_def_id) == lang_items.sized_trait() {
287-
if self_ty.is_trivially_sized(acx.cx.tcx) {
288-
acx.try_insert_candidate(CandidateSource::Builtin, Certainty::Yes);
289-
}
277+
acx.infcx.probe(|_| {
278+
let components = instantiate_constituent_tys_for_sized_trait(acx.infcx, self_ty);
279+
evaluate_goal_for_components(acx, goal, components, CandidateSource::Builtin);
280+
})
290281
} else if Some(trait_def_id) == lang_items.copy_trait()
291282
|| Some(trait_def_id) == lang_items.clone_trait()
292283
{
293-
// FIXME
284+
acx.infcx.probe(|_| {
285+
let components =
286+
instantiate_constituent_tys_for_copy_clone_trait(acx.infcx, self_ty);
287+
evaluate_goal_for_components(acx, goal, components, CandidateSource::Builtin);
288+
})
294289
} else if Some(trait_def_id) == lang_items.discriminant_kind_trait()
295290
|| Some(trait_def_id) == lang_items.pointee_trait()
296291
{
297292
// `Pointee` and `DiscriminantKind` are implemented by all traits unconditionally
298293
acx.try_insert_candidate(CandidateSource::Builtin, Certainty::Yes);
299294
} else if Some(trait_def_id) == lang_items.tuple_trait() {
300295
match *self_ty.kind() {
301-
ty::Infer(ty::TyVar(_)) => todo!("ambiguous"),
296+
ty::Infer(ty::TyVar(_)) => acx.try_insert_candidate(
297+
CandidateSource::Builtin,
298+
Certainty::Maybe(MaybeCause::Ambiguity),
299+
),
302300
ty::Tuple(_) => acx.try_insert_candidate(CandidateSource::Builtin, Certainty::Yes),
303301
_ => {}
304302
}
305303
} else if Some(trait_def_id) == lang_items.pointer_sized() {
306304
let erased_self_ty = acx.cx.tcx.erase_regions(self_ty);
307305
if erased_self_ty.has_non_region_infer() {
308-
todo!("ambiguous")
309-
}
310-
let usize_layout =
311-
acx.cx.tcx.layout_of(ty::ParamEnv::empty().and(acx.cx.tcx.types.usize)).unwrap();
312-
if let Ok(layout) = acx.cx.tcx.layout_of(goal.param_env.and(self_ty))
313-
&& layout.layout.size() == usize_layout.layout.size()
314-
&& layout.layout.align().abi == usize_layout.layout.align().abi
315-
{
316-
acx.try_insert_candidate(CandidateSource::Builtin, Certainty::Yes);
306+
acx.try_insert_candidate(
307+
CandidateSource::Builtin,
308+
Certainty::Maybe(MaybeCause::Ambiguity),
309+
)
310+
} else {
311+
let usize_layout = acx
312+
.cx
313+
.tcx
314+
.layout_of(ty::ParamEnv::empty().and(acx.cx.tcx.types.usize))
315+
.unwrap();
316+
if let Ok(layout) = acx.cx.tcx.layout_of(goal.param_env.and(self_ty))
317+
&& layout.layout.size() == usize_layout.layout.size()
318+
&& layout.layout.align().abi == usize_layout.layout.align().abi
319+
{
320+
acx.try_insert_candidate(CandidateSource::Builtin, Certainty::Yes);
321+
}
317322
}
318323
} else if Some(trait_def_id) == lang_items.coerce_unsized_trait()
319324
|| Some(trait_def_id) == lang_items.unsize_trait()
@@ -327,7 +332,7 @@ fn match_poly_trait_ref_against_goal<'tcx>(
327332
acx: &mut AssemblyCtxt<'_, 'tcx, TraitPredicate<'tcx>>,
328333
goal: Goal<'tcx, TraitPredicate<'tcx>>,
329334
trait_ref: ty::PolyTraitRef<'tcx>,
330-
candidate: impl FnOnce() -> CandidateSource,
335+
candidate: CandidateSource,
331336
) {
332337
acx.infcx.probe(|_| {
333338
let trait_ref = acx.infcx.replace_bound_vars_with_fresh_vars(
@@ -349,18 +354,57 @@ fn match_poly_trait_ref_against_goal<'tcx>(
349354
let nested_goals = obligations.into_iter().map(|o| o.into()).collect();
350355

351356
let Ok(certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return };
352-
acx.try_insert_candidate(candidate(), certainty);
357+
acx.try_insert_candidate(candidate, certainty);
353358
})
354359
}
355360

361+
// Evaluate the goal with a new set of self types, combined with a certainty.
362+
fn evaluate_goal_for_components<'tcx>(
363+
acx: &mut AssemblyCtxt<'_, 'tcx, TraitPredicate<'tcx>>,
364+
goal: Goal<'tcx, TraitPredicate<'tcx>>,
365+
components: ComponentsAndCertainty<'tcx>,
366+
candidate: CandidateSource,
367+
) {
368+
let components = match components {
369+
ComponentsAndCertainty::Yes(components) => components,
370+
ComponentsAndCertainty::Maybe => {
371+
acx.try_insert_candidate(candidate, Certainty::Maybe(MaybeCause::Ambiguity));
372+
return;
373+
}
374+
ComponentsAndCertainty::No => {
375+
return;
376+
}
377+
};
378+
379+
let nested_goals = components
380+
.into_iter()
381+
.map(|ty| {
382+
Goal::new(
383+
acx.cx.tcx,
384+
goal.param_env,
385+
ty::Binder::dummy(goal.predicate.with_self_ty(acx.cx.tcx, ty)),
386+
)
387+
})
388+
.collect();
389+
390+
let Ok(certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return };
391+
acx.try_insert_candidate(candidate, certainty);
392+
}
393+
394+
enum ComponentsAndCertainty<'tcx> {
395+
Yes(Vec<Ty<'tcx>>),
396+
Maybe,
397+
No,
398+
}
399+
356400
// Calculates the constituent types of a type for `auto trait` purposes.
357401
//
358402
// For types with an "existential" binder, i.e. generator witnesses, we also
359403
// instantiate the binder with placeholders eagerly.
360404
fn instantiate_constituent_tys_for_auto_trait<'tcx>(
361405
infcx: &InferCtxt<'tcx>,
362406
ty: Ty<'tcx>,
363-
) -> Result<Vec<Ty<'tcx>>, ()> {
407+
) -> ComponentsAndCertainty<'tcx> {
364408
let tcx = infcx.tcx;
365409
match *ty.kind() {
366410
ty::Uint(_)
@@ -373,53 +417,179 @@ fn instantiate_constituent_tys_for_auto_trait<'tcx>(
373417
| ty::Error(_)
374418
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
375419
| ty::Never
376-
| ty::Char => Ok(vec![]),
420+
| ty::Char => ComponentsAndCertainty::Yes(vec![]),
377421

378422
ty::Placeholder(..)
379423
| ty::Dynamic(..)
380424
| ty::Param(..)
381425
| ty::Foreign(..)
382426
| ty::Alias(ty::Projection, ..)
383-
| ty::Bound(..)
384-
| ty::Infer(ty::TyVar(_)) => {
385-
// FIXME: Do we need to mark anything as ambiguous here? Yeah?
386-
Err(())
387-
}
427+
| ty::Bound(..) => ComponentsAndCertainty::No,
428+
429+
ty::Infer(ty::TyVar(_)) => ComponentsAndCertainty::Maybe,
388430

389431
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
390432

391433
ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
392-
Ok(vec![element_ty])
434+
ComponentsAndCertainty::Yes(vec![element_ty])
393435
}
394436

395-
ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]),
437+
ty::Array(element_ty, _) | ty::Slice(element_ty) => {
438+
ComponentsAndCertainty::Yes(vec![element_ty])
439+
}
396440

397441
ty::Tuple(ref tys) => {
398442
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
399-
Ok(tys.iter().collect())
443+
ComponentsAndCertainty::Yes(tys.iter().collect())
400444
}
401445

402-
ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]),
446+
ty::Closure(_, ref substs) => {
447+
ComponentsAndCertainty::Yes(vec![substs.as_closure().tupled_upvars_ty()])
448+
}
403449

404450
ty::Generator(_, ref substs, _) => {
405451
let generator_substs = substs.as_generator();
406-
Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()])
452+
ComponentsAndCertainty::Yes(vec![
453+
generator_substs.tupled_upvars_ty(),
454+
generator_substs.witness(),
455+
])
407456
}
408457

409458
ty::GeneratorWitness(types) => {
410-
Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
459+
ComponentsAndCertainty::Yes(infcx.replace_bound_vars_with_placeholders(types).to_vec())
411460
}
412461

413462
// For `PhantomData<T>`, we pass `T`.
414-
ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]),
463+
ty::Adt(def, substs) if def.is_phantom_data() => {
464+
ComponentsAndCertainty::Yes(vec![substs.type_at(0)])
465+
}
415466

416-
ty::Adt(def, substs) => Ok(def.all_fields().map(|f| f.ty(tcx, substs)).collect()),
467+
ty::Adt(def, substs) => {
468+
ComponentsAndCertainty::Yes(def.all_fields().map(|f| f.ty(tcx, substs)).collect())
469+
}
417470

418471
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
419472
// We can resolve the `impl Trait` to its concrete type,
420473
// which enforces a DAG between the functions requiring
421474
// the auto trait bounds in question.
422-
Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)])
475+
ComponentsAndCertainty::Yes(vec![tcx.bound_type_of(def_id).subst(tcx, substs)])
476+
}
477+
}
478+
}
479+
480+
fn instantiate_constituent_tys_for_sized_trait<'tcx>(
481+
infcx: &InferCtxt<'tcx>,
482+
ty: Ty<'tcx>,
483+
) -> ComponentsAndCertainty<'tcx> {
484+
match *ty.kind() {
485+
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
486+
| ty::Uint(_)
487+
| ty::Int(_)
488+
| ty::Bool
489+
| ty::Float(_)
490+
| ty::FnDef(..)
491+
| ty::FnPtr(_)
492+
| ty::RawPtr(..)
493+
| ty::Char
494+
| ty::Ref(..)
495+
| ty::Generator(..)
496+
| ty::GeneratorWitness(..)
497+
| ty::Array(..)
498+
| ty::Closure(..)
499+
| ty::Never
500+
| ty::Dynamic(_, _, ty::DynStar)
501+
| ty::Error(_) => ComponentsAndCertainty::Yes(vec![]),
502+
503+
ty::Str
504+
| ty::Slice(_)
505+
| ty::Dynamic(..)
506+
| ty::Foreign(..)
507+
| ty::Alias(..)
508+
| ty::Param(_) => ComponentsAndCertainty::No,
509+
510+
ty::Infer(ty::TyVar(_)) => ComponentsAndCertainty::Maybe,
511+
512+
ty::Placeholder(..)
513+
| ty::Bound(..)
514+
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
515+
516+
ty::Tuple(tys) => ComponentsAndCertainty::Yes(tys.to_vec()),
517+
518+
ty::Adt(def, substs) => {
519+
let sized_crit = def.sized_constraint(infcx.tcx);
520+
ComponentsAndCertainty::Yes(
521+
sized_crit
522+
.0
523+
.iter()
524+
.map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs))
525+
.collect(),
526+
)
527+
}
528+
}
529+
}
530+
531+
fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
532+
infcx: &InferCtxt<'tcx>,
533+
ty: Ty<'tcx>,
534+
) -> ComponentsAndCertainty<'tcx> {
535+
match *ty.kind() {
536+
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
537+
| ty::FnDef(..)
538+
| ty::FnPtr(_)
539+
| ty::Error(_) => ComponentsAndCertainty::Yes(vec![]),
540+
541+
// Implementations are provided in core
542+
ty::Uint(_)
543+
| ty::Int(_)
544+
| ty::Bool
545+
| ty::Float(_)
546+
| ty::Char
547+
| ty::RawPtr(..)
548+
| ty::Never
549+
| ty::Ref(_, _, Mutability::Not)
550+
| ty::Array(..) => ComponentsAndCertainty::No,
551+
552+
ty::Dynamic(..)
553+
| ty::Str
554+
| ty::Slice(_)
555+
| ty::Generator(_, _, Movability::Static)
556+
| ty::Foreign(..)
557+
| ty::Ref(_, _, Mutability::Mut)
558+
| ty::Adt(_, _)
559+
| ty::Alias(_, _)
560+
| ty::Param(_) => ComponentsAndCertainty::No,
561+
562+
ty::Infer(ty::TyVar(_)) => ComponentsAndCertainty::Maybe,
563+
564+
ty::Placeholder(..)
565+
| ty::Bound(..)
566+
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
567+
568+
ty::Tuple(tys) => ComponentsAndCertainty::Yes(tys.to_vec()),
569+
570+
ty::Closure(_, substs) => match *substs.as_closure().tupled_upvars_ty().kind() {
571+
ty::Tuple(tys) => ComponentsAndCertainty::Yes(tys.to_vec()),
572+
ty::Infer(ty::TyVar(_)) => ComponentsAndCertainty::Maybe,
573+
_ => bug!(),
574+
},
575+
576+
ty::Generator(_, substs, Movability::Movable) => {
577+
if infcx.tcx.features().generator_clone {
578+
let generator = substs.as_generator();
579+
match *generator.tupled_upvars_ty().kind() {
580+
ty::Tuple(tys) => ComponentsAndCertainty::Yes(
581+
tys.iter().chain([generator.witness()]).collect(),
582+
),
583+
ty::Infer(ty::TyVar(_)) => ComponentsAndCertainty::Maybe,
584+
_ => bug!(),
585+
}
586+
} else {
587+
ComponentsAndCertainty::No
588+
}
589+
}
590+
591+
ty::GeneratorWitness(types) => {
592+
ComponentsAndCertainty::Yes(infcx.replace_bound_vars_with_placeholders(types).to_vec())
423593
}
424594
}
425595
}

0 commit comments

Comments
 (0)