Skip to content

Commit 7d4ea10

Browse files
committed
Add built-in const impls for Clone and Copy
1 parent 6380899 commit 7d4ea10

File tree

5 files changed

+133
-8
lines changed

5 files changed

+133
-8
lines changed

compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,32 @@ where
211211
}
212212

213213
fn consider_builtin_copy_clone_candidate(
214-
_ecx: &mut EvalCtxt<'_, D>,
215-
_goal: Goal<I, Self>,
214+
ecx: &mut EvalCtxt<'_, D>,
215+
goal: Goal<I, Self>,
216216
) -> Result<Candidate<I>, NoSolution> {
217-
Err(NoSolution)
217+
let cx = ecx.cx();
218+
219+
let self_ty = goal.predicate.self_ty();
220+
let constituent_tys =
221+
structural_traits::instantiate_constituent_tys_for_copy_clone_trait(ecx, self_ty)?;
222+
223+
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
224+
ecx.enter_forall(constituent_tys, |ecx, tys| {
225+
ecx.add_goals(
226+
GoalSource::ImplWhereBound,
227+
tys.into_iter().map(|ty| {
228+
goal.with(
229+
cx,
230+
ty::ClauseKind::HostEffect(
231+
goal.predicate.with_replaced_self_ty(cx, ty),
232+
),
233+
)
234+
}),
235+
);
236+
});
237+
238+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
239+
})
218240
}
219241

220242
fn consider_builtin_fn_ptr_trait_candidate(

compiler/rustc_trait_selection/src/traits/effects.rs

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_middle::span_bug;
88
use rustc_middle::traits::query::NoSolution;
99
use rustc_middle::ty::elaborate::elaborate;
1010
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
11-
use rustc_middle::ty::{self, TypingMode};
11+
use rustc_middle::ty::{self, Ty, TypingMode};
1212
use thin_vec::{ThinVec, thin_vec};
1313

1414
use super::SelectionContext;
@@ -303,6 +303,9 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>(
303303
obligation: &HostEffectObligation<'tcx>,
304304
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
305305
match selcx.tcx().as_lang_item(obligation.predicate.def_id()) {
306+
Some(LangItem::Copy | LangItem::Clone) => {
307+
evaluate_host_effect_for_copy_clone_goal(selcx, obligation)
308+
}
306309
Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation),
307310
Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => {
308311
evaluate_host_effect_for_fn_goal(selcx, obligation)
@@ -311,6 +314,95 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>(
311314
}
312315
}
313316

317+
fn evaluate_host_effect_for_copy_clone_goal<'tcx>(
318+
selcx: &mut SelectionContext<'_, 'tcx>,
319+
obligation: &HostEffectObligation<'tcx>,
320+
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
321+
let tcx = selcx.tcx();
322+
let self_ty = obligation.predicate.self_ty();
323+
let constituent_tys = match *self_ty.kind() {
324+
// impl Copy/Clone for FnDef, FnPtr
325+
ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])),
326+
327+
// Implementations are provided in core
328+
ty::Uint(_)
329+
| ty::Int(_)
330+
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
331+
| ty::Bool
332+
| ty::Float(_)
333+
| ty::Char
334+
| ty::RawPtr(..)
335+
| ty::Never
336+
| ty::Ref(_, _, ty::Mutability::Not)
337+
| ty::Array(..) => Err(EvaluationFailure::NoSolution),
338+
339+
// Cannot implement in core, as we can't be generic over patterns yet,
340+
// so we'd have to list all patterns and type combinations.
341+
ty::Pat(ty, ..) => Ok(ty::Binder::dummy(vec![ty])),
342+
343+
ty::Dynamic(..)
344+
| ty::Str
345+
| ty::Slice(_)
346+
| ty::Foreign(..)
347+
| ty::Ref(_, _, ty::Mutability::Mut)
348+
| ty::Adt(_, _)
349+
| ty::Alias(_, _)
350+
| ty::Param(_)
351+
| ty::Placeholder(..) => Err(EvaluationFailure::NoSolution),
352+
353+
ty::Bound(..)
354+
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
355+
panic!("unexpected type `{self_ty:?}`")
356+
}
357+
358+
// impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone
359+
ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.to_vec())),
360+
361+
// impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone
362+
ty::Closure(_, args) => Ok(ty::Binder::dummy(vec![args.as_closure().tupled_upvars_ty()])),
363+
364+
// impl Copy/Clone for CoroutineClosure where Self::TupledUpvars: Copy/Clone
365+
ty::CoroutineClosure(_, args) => {
366+
Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()]))
367+
}
368+
369+
// only when `coroutine_clone` is enabled and the coroutine is movable
370+
// impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses)
371+
ty::Coroutine(def_id, args) => match tcx.coroutine_movability(def_id) {
372+
ty::Movability::Static => Err(EvaluationFailure::NoSolution),
373+
ty::Movability::Movable => {
374+
if tcx.features().coroutine_clone() {
375+
Ok(ty::Binder::dummy(vec![
376+
args.as_coroutine().tupled_upvars_ty(),
377+
Ty::new_coroutine_witness_for_coroutine(tcx, def_id, args),
378+
]))
379+
} else {
380+
Err(EvaluationFailure::NoSolution)
381+
}
382+
}
383+
},
384+
385+
ty::UnsafeBinder(_) => Err(EvaluationFailure::NoSolution),
386+
387+
// impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
388+
ty::CoroutineWitness(def_id, args) => Ok(tcx
389+
.coroutine_hidden_types(def_id)
390+
.instantiate(tcx, args)
391+
.map_bound(|bound| bound.types.to_vec())),
392+
}?;
393+
394+
Ok(constituent_tys
395+
.iter()
396+
.map(|ty| {
397+
obligation.with(
398+
tcx,
399+
ty.map_bound(|ty| ty::TraitRef::new(tcx, obligation.predicate.def_id(), [ty]))
400+
.to_host_effect_clause(tcx, obligation.predicate.constness),
401+
)
402+
})
403+
.collect())
404+
}
405+
314406
// NOTE: Keep this in sync with `const_conditions_for_destruct` in the new solver.
315407
fn evaluate_host_effect_for_destruct_goal<'tcx>(
316408
selcx: &mut SelectionContext<'_, 'tcx>,

compiler/rustc_type_ir/src/predicate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ impl<I: Interner> ty::Binder<I, TraitRef<I>> {
121121
}
122122

123123
pub fn to_host_effect_clause(self, cx: I, constness: BoundConstness) -> I::Clause {
124-
self.map_bound(|trait_ref| {
124+
self.map_bound(|trait_ref: TraitRef<I>| {
125125
ty::ClauseKind::HostEffect(HostEffectPredicate { trait_ref, constness })
126126
})
127127
.upcast(cx)

tests/ui/traits/const-traits/const-traits-alloc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ run-pass
1+
//@ check-pass
22
#![feature(const_trait_impl, const_default)]
33
#![allow(dead_code)]
44
// alloc::string

tests/ui/traits/const-traits/const-traits-core.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
//@ run-pass
1+
//@ check-pass
22
#![feature(
3-
const_trait_impl, const_default, ptr_alignment_type, ascii_char, f16, f128, sync_unsafe_cell,
3+
const_clone,
4+
const_default,
5+
const_trait_impl,
6+
ptr_alignment_type,
7+
ascii_char,
8+
f16,
9+
f128,
10+
sync_unsafe_cell,
411
)]
512
#![allow(dead_code)]
613
// core::default
@@ -43,4 +50,8 @@ const REF_CELL: std::cell::RefCell<()> = Default::default();
4350
const UNSAFE_CELL: std::cell::UnsafeCell<()> = Default::default();
4451
const SYNC_UNSAFE_CELL: std::cell::SyncUnsafeCell<()> = Default::default();
4552

53+
// `Clone` for tuples
54+
const BUILTIN_CLONE: () = ().clone();
55+
const BUILTIN_CLONE_2: (u32, i32) = (42, 100).clone();
56+
4657
fn main() {}

0 commit comments

Comments
 (0)