Skip to content

Commit c75e089

Browse files
committed
chalkify: Add Copy/Clone builtins
1 parent b2c0fd0 commit c75e089

File tree

3 files changed

+192
-21
lines changed

3 files changed

+192
-21
lines changed

src/librustc_traits/chalk_context/program_clauses/builtin.rs

+129-20
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,42 @@ use rustc::traits::{
66
};
77
use rustc::ty;
88
use rustc::ty::subst::{InternalSubsts, Subst};
9+
use rustc::hir;
910
use rustc::hir::def_id::DefId;
1011
use crate::lowering::Lower;
1112
use crate::generic_types;
1213

14+
/// Returns a predicate of the form
15+
/// `Implemented(ty: Trait) :- Implemented(nested: Trait)...`
16+
/// where `Trait` is specified by `trait_def_id`.
17+
fn builtin_impl_clause(
18+
tcx: ty::TyCtxt<'_, '_, 'tcx>,
19+
ty: ty::Ty<'tcx>,
20+
nested: &[ty::Ty<'tcx>],
21+
trait_def_id: DefId
22+
) -> ProgramClause<'tcx> {
23+
ProgramClause {
24+
goal: ty::TraitPredicate {
25+
trait_ref: ty::TraitRef {
26+
def_id: trait_def_id,
27+
substs: tcx.mk_substs_trait(ty, &[]),
28+
},
29+
}.lower(),
30+
hypotheses: tcx.mk_goals(
31+
nested.iter()
32+
.cloned()
33+
.map(|nested_ty| ty::TraitRef {
34+
def_id: trait_def_id,
35+
substs: tcx.mk_substs_trait(nested_ty, &[]),
36+
})
37+
.map(|trait_ref| ty::TraitPredicate { trait_ref })
38+
.map(|pred| GoalKind::DomainGoal(pred.lower()))
39+
.map(|goal_kind| tcx.mk_goal(goal_kind))
40+
),
41+
category: ProgramClauseCategory::Other,
42+
}
43+
}
44+
1345
crate fn assemble_builtin_unsize_impls<'tcx>(
1446
tcx: ty::TyCtxt<'_, '_, 'tcx>,
1547
unsize_def_id: DefId,
@@ -93,26 +125,7 @@ crate fn assemble_builtin_sized_impls<'tcx>(
93125
clauses: &mut Vec<Clause<'tcx>>
94126
) {
95127
let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| {
96-
let clause = ProgramClause {
97-
goal: ty::TraitPredicate {
98-
trait_ref: ty::TraitRef {
99-
def_id: sized_def_id,
100-
substs: tcx.mk_substs_trait(ty, &[]),
101-
},
102-
}.lower(),
103-
hypotheses: tcx.mk_goals(
104-
nested.iter()
105-
.cloned()
106-
.map(|nested_ty| ty::TraitRef {
107-
def_id: sized_def_id,
108-
substs: tcx.mk_substs_trait(nested_ty, &[]),
109-
})
110-
.map(|trait_ref| ty::TraitPredicate { trait_ref })
111-
.map(|pred| GoalKind::DomainGoal(pred.lower()))
112-
.map(|goal_kind| tcx.mk_goal(goal_kind))
113-
),
114-
category: ProgramClauseCategory::Other,
115-
};
128+
let clause = builtin_impl_clause(tcx, ty, nested, sized_def_id);
116129
// Bind innermost bound vars that may exist in `ty` and `nested`.
117130
clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
118131
};
@@ -206,3 +219,99 @@ crate fn assemble_builtin_sized_impls<'tcx>(
206219
ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty),
207220
}
208221
}
222+
223+
crate fn assemble_builtin_copy_clone_impls<'tcx>(
224+
tcx: ty::TyCtxt<'_, '_, 'tcx>,
225+
trait_def_id: DefId,
226+
ty: ty::Ty<'tcx>,
227+
clauses: &mut Vec<Clause<'tcx>>
228+
) {
229+
let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| {
230+
let clause = builtin_impl_clause(tcx, ty, nested, trait_def_id);
231+
// Bind innermost bound vars that may exist in `ty` and `nested`.
232+
clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
233+
};
234+
235+
match &ty.sty {
236+
// Implementations provided in libcore.
237+
ty::Bool |
238+
ty::Char |
239+
ty::Int(..) |
240+
ty::Uint(..) |
241+
ty::Float(..) |
242+
ty::RawPtr(..) |
243+
ty::Never |
244+
ty::Ref(_, _, hir::MutImmutable) => (),
245+
246+
// Non parametric primitive type.
247+
ty::Error => push_builtin_impl(ty, &[]),
248+
249+
// These implement `Copy`/`Clone` if their element types do.
250+
&ty::Array(_, length) => {
251+
let element_ty = generic_types::bound(tcx, 0);
252+
push_builtin_impl(tcx.mk_ty(ty::Array(element_ty, length)), &[element_ty]);
253+
}
254+
&ty::Tuple(type_list) => {
255+
let type_list = generic_types::type_list(tcx, type_list.len());
256+
push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list);
257+
}
258+
&ty::Closure(def_id, ..) => {
259+
let closure_ty = generic_types::closure(tcx, def_id);
260+
let upvar_tys: Vec<_> = match &closure_ty.sty {
261+
ty::Closure(_, substs) => substs.upvar_tys(def_id, tcx).collect(),
262+
_ => bug!(),
263+
};
264+
push_builtin_impl(closure_ty, &upvar_tys);
265+
}
266+
267+
// These ones are always `Clone`.
268+
ty::FnPtr(fn_ptr) => {
269+
let fn_ptr = fn_ptr.skip_binder();
270+
let fn_ptr = generic_types::fn_ptr(
271+
tcx,
272+
fn_ptr.inputs_and_output.len(),
273+
fn_ptr.c_variadic,
274+
fn_ptr.unsafety,
275+
fn_ptr.abi
276+
);
277+
push_builtin_impl(fn_ptr, &[]);
278+
}
279+
&ty::FnDef(def_id, ..) => {
280+
push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]);
281+
}
282+
283+
// These depend on whatever user-defined impls might exist.
284+
ty::Adt(_, _) => (),
285+
286+
// int vars and float vars are always `Copy`.
287+
// Other vars will trigger an ambiguity.
288+
ty::Infer(..) => {
289+
push_builtin_impl(tcx.types.i32, &[]);
290+
push_builtin_impl(tcx.types.u32, &[]);
291+
push_builtin_impl(tcx.types.f32, &[]);
292+
push_builtin_impl(tcx.types.f64, &[]);
293+
}
294+
295+
ty::Projection(_projection_ty) => {
296+
// FIXME: add builtin impls from the associated type values found in
297+
// trait impls of `projection_ty.trait_ref(tcx)`.
298+
}
299+
300+
// The `Copy`/`Clone` bound can only come from the environment.
301+
ty::Param(..) |
302+
ty::Placeholder(..) |
303+
ty::UnnormalizedProjection(..) |
304+
ty::Opaque(..) => (),
305+
306+
// Definitely not `Copy`/`Clone`.
307+
ty::Dynamic(..) |
308+
ty::Foreign(..) |
309+
ty::Generator(..) |
310+
ty::Str |
311+
ty::Slice(..) |
312+
ty::Ref(_, _, hir::MutMutable) => (),
313+
314+
ty::Bound(..) |
315+
ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty),
316+
}
317+
}

src/librustc_traits/chalk_context/program_clauses/mod.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,27 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> {
9696
);
9797
}
9898

99+
if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().copy_trait() {
100+
assemble_builtin_copy_clone_impls(
101+
self.infcx.tcx,
102+
trait_predicate.def_id(),
103+
trait_predicate.self_ty(),
104+
&mut clauses
105+
);
106+
}
107+
108+
if Some(trait_predicate.def_id()) == self.infcx.tcx.lang_items().clone_trait() {
109+
// For all builtin impls, the conditions for `Copy` and
110+
// `Clone` are the same.
111+
assemble_builtin_copy_clone_impls(
112+
self.infcx.tcx,
113+
trait_predicate.def_id(),
114+
trait_predicate.self_ty(),
115+
&mut clauses
116+
);
117+
}
118+
99119
// FIXME: we need to add special rules for other builtin impls:
100-
// * `Copy` / `Clone`
101120
// * `Generator`
102121
// * `FnOnce` / `FnMut` / `Fn`
103122
// * trait objects
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// compile-flags: -Z chalk
2+
3+
// Test that `Clone` is correctly implemented for builtin types.
4+
5+
#[derive(Copy, Clone)]
6+
struct S(i32);
7+
8+
fn test_clone<T: Clone>(arg: T) {
9+
let _ = arg.clone();
10+
}
11+
12+
fn test_copy<T: Copy>(arg: T) {
13+
let _ = arg;
14+
let _ = arg;
15+
}
16+
17+
fn test_copy_clone<T: Copy + Clone>(arg: T) {
18+
test_copy(arg);
19+
test_clone(arg);
20+
}
21+
22+
fn foo() { }
23+
24+
fn main() {
25+
test_copy_clone(foo);
26+
let f: fn() = foo;
27+
test_copy_clone(f);
28+
// FIXME: add closures when they're considered WF
29+
test_copy_clone([1; 56]);
30+
test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1));
31+
test_copy_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, true, 'a', 1.1));
32+
test_copy_clone(());
33+
test_copy_clone(((1, 1), (1, 1, 1), (1.1, 1, 1, 'a'), ()));
34+
35+
let a = (
36+
(S(1), S(0)),
37+
(
38+
(S(0), S(0), S(1)),
39+
S(0)
40+
)
41+
);
42+
test_copy_clone(a);
43+
}

0 commit comments

Comments
 (0)