Skip to content

Commit 7cdb49d

Browse files
authored
Rollup merge of rust-lang#60183 - tmandry:chalk-builtin-copy-clone, r=scalexm
Chalkify: Add builtin Copy/Clone r? @nikomatsakis
2 parents 63adb5e + 56ab3e7 commit 7cdb49d

File tree

4 files changed

+208
-38
lines changed

4 files changed

+208
-38
lines changed

src/librustc/traits/select.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -2505,16 +2505,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
25052505
}
25062506

25072507
ty::Closure(def_id, substs) => {
2508-
let trait_id = obligation.predicate.def_id();
2509-
let is_copy_trait = Some(trait_id) == self.tcx().lang_items().copy_trait();
2510-
let is_clone_trait = Some(trait_id) == self.tcx().lang_items().clone_trait();
2511-
if is_copy_trait || is_clone_trait {
2512-
Where(ty::Binder::bind(
2513-
substs.upvar_tys(def_id, self.tcx()).collect(),
2514-
))
2515-
} else {
2516-
None
2517-
}
2508+
// (*) binder moved here
2509+
Where(ty::Binder::bind(
2510+
substs.upvar_tys(def_id, self.tcx()).collect(),
2511+
))
25182512
}
25192513

25202514
ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {

src/librustc_traits/chalk_context/program_clauses/builtin.rs

+141-27
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
};
@@ -124,6 +137,8 @@ crate fn assemble_builtin_sized_impls<'tcx>(
124137
ty::Int(..) |
125138
ty::Uint(..) |
126139
ty::Float(..) |
140+
ty::Infer(ty::IntVar(_)) |
141+
ty::Infer(ty::FloatVar(_)) |
127142
ty::Error |
128143
ty::Never => push_builtin_impl(ty, &[]),
129144

@@ -175,14 +190,11 @@ crate fn assemble_builtin_sized_impls<'tcx>(
175190
push_builtin_impl(adt, &sized_constraint);
176191
}
177192

178-
// Artificially trigger an ambiguity.
179-
ty::Infer(..) => {
180-
// Everybody can find at least two types to unify against:
181-
// general ty vars, int vars and float vars.
193+
// Artificially trigger an ambiguity by adding two possible types to
194+
// unify against.
195+
ty::Infer(ty::TyVar(_)) => {
182196
push_builtin_impl(tcx.types.i32, &[]);
183-
push_builtin_impl(tcx.types.u32, &[]);
184197
push_builtin_impl(tcx.types.f32, &[]);
185-
push_builtin_impl(tcx.types.f64, &[]);
186198
}
187199

188200
ty::Projection(_projection_ty) => {
@@ -203,6 +215,108 @@ crate fn assemble_builtin_sized_impls<'tcx>(
203215
ty::Opaque(..) => (),
204216

205217
ty::Bound(..) |
206-
ty::GeneratorWitness(..) => bug!("unexpected type {:?}", ty),
218+
ty::GeneratorWitness(..) |
219+
ty::Infer(ty::FreshTy(_)) |
220+
ty::Infer(ty::FreshIntTy(_)) |
221+
ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty),
222+
}
223+
}
224+
225+
crate fn assemble_builtin_copy_clone_impls<'tcx>(
226+
tcx: ty::TyCtxt<'_, '_, 'tcx>,
227+
trait_def_id: DefId,
228+
ty: ty::Ty<'tcx>,
229+
clauses: &mut Vec<Clause<'tcx>>
230+
) {
231+
let mut push_builtin_impl = |ty: ty::Ty<'tcx>, nested: &[ty::Ty<'tcx>]| {
232+
let clause = builtin_impl_clause(tcx, ty, nested, trait_def_id);
233+
// Bind innermost bound vars that may exist in `ty` and `nested`.
234+
clauses.push(Clause::ForAll(ty::Binder::bind(clause)));
235+
};
236+
237+
match &ty.sty {
238+
// Implementations provided in libcore.
239+
ty::Bool |
240+
ty::Char |
241+
ty::Int(..) |
242+
ty::Uint(..) |
243+
ty::Float(..) |
244+
ty::RawPtr(..) |
245+
ty::Never |
246+
ty::Ref(_, _, hir::MutImmutable) => (),
247+
248+
// Non parametric primitive types.
249+
ty::Infer(ty::IntVar(_)) |
250+
ty::Infer(ty::FloatVar(_)) |
251+
ty::Error => push_builtin_impl(ty, &[]),
252+
253+
// These implement `Copy`/`Clone` if their element types do.
254+
&ty::Array(_, length) => {
255+
let element_ty = generic_types::bound(tcx, 0);
256+
push_builtin_impl(tcx.mk_ty(ty::Array(element_ty, length)), &[element_ty]);
257+
}
258+
&ty::Tuple(type_list) => {
259+
let type_list = generic_types::type_list(tcx, type_list.len());
260+
push_builtin_impl(tcx.mk_ty(ty::Tuple(type_list)), &**type_list);
261+
}
262+
&ty::Closure(def_id, ..) => {
263+
let closure_ty = generic_types::closure(tcx, def_id);
264+
let upvar_tys: Vec<_> = match &closure_ty.sty {
265+
ty::Closure(_, substs) => substs.upvar_tys(def_id, tcx).collect(),
266+
_ => bug!(),
267+
};
268+
push_builtin_impl(closure_ty, &upvar_tys);
269+
}
270+
271+
// These ones are always `Clone`.
272+
ty::FnPtr(fn_ptr) => {
273+
let fn_ptr = fn_ptr.skip_binder();
274+
let fn_ptr = generic_types::fn_ptr(
275+
tcx,
276+
fn_ptr.inputs_and_output.len(),
277+
fn_ptr.c_variadic,
278+
fn_ptr.unsafety,
279+
fn_ptr.abi
280+
);
281+
push_builtin_impl(fn_ptr, &[]);
282+
}
283+
&ty::FnDef(def_id, ..) => {
284+
push_builtin_impl(generic_types::fn_def(tcx, def_id), &[]);
285+
}
286+
287+
// These depend on whatever user-defined impls might exist.
288+
ty::Adt(_, _) => (),
289+
290+
// Artificially trigger an ambiguity by adding two possible types to
291+
// unify against.
292+
ty::Infer(ty::TyVar(_)) => {
293+
push_builtin_impl(tcx.types.i32, &[]);
294+
push_builtin_impl(tcx.types.f32, &[]);
295+
}
296+
297+
ty::Projection(_projection_ty) => {
298+
// FIXME: add builtin impls from the associated type values found in
299+
// trait impls of `projection_ty.trait_ref(tcx)`.
300+
}
301+
302+
// The `Copy`/`Clone` bound can only come from the environment.
303+
ty::Param(..) |
304+
ty::Placeholder(..) |
305+
ty::UnnormalizedProjection(..) |
306+
ty::Opaque(..) => (),
307+
308+
// Definitely not `Copy`/`Clone`.
309+
ty::Dynamic(..) |
310+
ty::Foreign(..) |
311+
ty::Generator(..) |
312+
ty::Str |
313+
ty::Slice(..) |
314+
ty::Ref(_, _, hir::MutMutable) => (),
315+
316+
ty::Bound(..) |
317+
ty::GeneratorWitness(..) |
318+
ty::Infer(ty::FreshTy(_)) |
319+
ty::Infer(ty::FreshIntTy(_)) |
320+
ty::Infer(ty::FreshFloatTy(_)) => bug!("unexpected type {:?}", ty),
207321
}
208322
}

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)