Skip to content

Commit 4d97033

Browse files
committed
Type check defaults.
And refactor duplicated code.
1 parent 0ff9872 commit 4d97033

File tree

4 files changed

+218
-22
lines changed

4 files changed

+218
-22
lines changed

src/librustc_typeck/check/wfcheck.rs

Lines changed: 124 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
185185
reject_shadowing_type_parameters(fcx.tcx, item.def_id);
186186
let sig = fcx.tcx.fn_sig(item.def_id);
187187
let sig = fcx.normalize_associated_types_in(span, &sig);
188-
let predicates = fcx.tcx.predicates_of(item.def_id)
189-
.instantiate_identity(fcx.tcx);
190-
let predicates = fcx.normalize_associated_types_in(span, &predicates);
191-
this.check_fn_or_method(fcx, span, sig, &predicates,
188+
this.check_fn_or_method(fcx, span, sig,
192189
item.def_id, &mut implied_bounds);
193190
let sig_if_method = sig_if_method.expect("bad signature for method");
194191
this.check_method_receiver(fcx, sig_if_method, &item, self_ty);
@@ -272,20 +269,17 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
272269
}
273270
}
274271

275-
let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
276-
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
277-
this.check_where_clauses(fcx, item.span, &predicates);
272+
self.check_where_clauses(fcx, item.span, def_id);
278273

279274
vec![] // no implied bounds in a struct def'n
280275
});
281276
}
282277

283278
fn check_trait(&mut self, item: &hir::Item) {
284279
let trait_def_id = self.tcx.hir.local_def_id(item.id);
285-
self.for_item(item).with_fcx(|fcx, this| {
286-
let predicates = fcx.tcx.predicates_of(trait_def_id).instantiate_identity(fcx.tcx);
287-
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
288-
this.check_where_clauses(fcx, item.span, &predicates);
280+
281+
self.for_item(item).with_fcx(|fcx, _| {
282+
self.check_where_clauses(fcx, item.span, trait_def_id);
289283
vec![]
290284
});
291285
}
@@ -295,12 +289,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
295289
let def_id = fcx.tcx.hir.local_def_id(item.id);
296290
let sig = fcx.tcx.fn_sig(def_id);
297291
let sig = fcx.normalize_associated_types_in(item.span, &sig);
298-
299-
let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
300-
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
301-
302292
let mut implied_bounds = vec![];
303-
this.check_fn_or_method(fcx, item.span, sig, &predicates,
293+
this.check_fn_or_method(fcx, item.span, sig,
304294
def_id, &mut implied_bounds);
305295
implied_bounds
306296
})
@@ -354,19 +344,132 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
354344
}
355345
}
356346

357-
let predicates = fcx.tcx.predicates_of(item_def_id).instantiate_identity(fcx.tcx);
358-
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
359-
this.check_where_clauses(fcx, item.span, &predicates);
347+
this.check_where_clauses(fcx, item.span, item_def_id);
360348

361349
fcx.impl_implied_bounds(item_def_id, item.span)
362350
});
363351
}
364352

353+
/// Checks where clauses and inline bounds.
365354
fn check_where_clauses<'fcx, 'tcx>(&mut self,
366355
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
367356
span: Span,
368-
predicates: &ty::InstantiatedPredicates<'tcx>)
357+
def_id: DefId)
369358
{
359+
use ty::subst::Subst;
360+
use ty::Predicate;
361+
362+
// Check that each default fulfills the bounds on it's parameter.
363+
// We go over each predicate and duplicate it, substituting defaults in the self type.
364+
let mut predicates = fcx.tcx.predicates_of(def_id);
365+
let mut default_predicates = Vec::new();
366+
for pred in &predicates.predicates {
367+
let mut self_ty = match pred {
368+
Predicate::Trait(trait_pred) => trait_pred.skip_binder().self_ty(),
369+
Predicate::TypeOutlives(outlives_pred) => (outlives_pred.0).0,
370+
Predicate::Projection(proj_pred) => {
371+
fcx.tcx.mk_ty(ty::TyProjection(proj_pred.skip_binder().projection_ty))
372+
}
373+
// Lifetime params can't have defaults.
374+
Predicate::RegionOutlives(..) => continue,
375+
_ => bug!("Predicate {:?} not supported in where clauses.", pred)
376+
};
377+
378+
let mut skip = false;
379+
let mut no_default = true;
380+
let generics = self.tcx.generics_of(def_id);
381+
let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
382+
// All regions are identity.
383+
fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
384+
}, |def, _| {
385+
// No default or generic comes from parent, identity substitution.
386+
if !def.has_default || (def.index as usize) < generics.parent_count() {
387+
fcx.tcx.mk_param_from_def(def)
388+
} else {
389+
no_default = false;
390+
// Has a default, use it in the substitution.
391+
let default_ty = fcx.tcx.type_of(def.def_id);
392+
// Skip `Self : Self` in traits, it's problematic.
393+
// This means we probably check less than we could.
394+
let should_skip = match self_ty.sty {
395+
ty::TyParam(ref p) => {
396+
// lhs is Self && rhs is Self
397+
p.is_self() && match pred {
398+
Predicate::Trait(p) => p.def_id() == def_id,
399+
Predicate::TypeOutlives(_) => false,
400+
_ => bug!("Unexpected predicate {:?}", pred)
401+
}
402+
}
403+
ty::TyProjection(ref proj) => {
404+
let mut projection = proj;
405+
let mut next_typ = &projection.substs[0].as_type().unwrap().sty;
406+
// Dig through projections.
407+
while let ty::TyProjection(ref proj) = next_typ {
408+
projection = proj;
409+
next_typ = &projection.substs[0].as_type().unwrap().sty;
410+
}
411+
let lhs_is_self = match next_typ {
412+
ty::TyParam(ref p) => p.is_self(),
413+
_ => false
414+
};
415+
let rhs = fcx.tcx.associated_item(projection.item_def_id)
416+
.container
417+
.assert_trait();
418+
lhs_is_self && rhs == def_id
419+
}
420+
_ => false
421+
};
422+
skip = skip || should_skip;
423+
424+
match default_ty.sty {
425+
// Skip `Self: Sized` when `Self` is the default. Needed in traits.
426+
ty::TyParam(ref p) if p.is_self() => {
427+
if let Predicate::Trait(p) = pred {
428+
if Some(p.def_id()) == fcx.tcx.lang_items().sized_trait() {
429+
skip = true;
430+
}
431+
}
432+
}
433+
_ => ()
434+
}
435+
default_ty
436+
}
437+
});
438+
439+
if skip || no_default {
440+
continue;
441+
}
442+
443+
self_ty = self_ty.subst(fcx.tcx, substs);
444+
default_predicates.push(match pred {
445+
Predicate::Trait(trait_pred) => {
446+
let mut substs = trait_pred.skip_binder().trait_ref.substs.to_vec();
447+
substs[0] = self_ty.into();
448+
let substs = fcx.tcx.intern_substs(&substs);
449+
let trait_ref = ty::Binder(ty::TraitRef::new(trait_pred.def_id(), substs));
450+
Predicate::Trait(trait_ref.to_poly_trait_predicate())
451+
}
452+
Predicate::TypeOutlives(pred) => {
453+
Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(self_ty, (pred.0).1)))
454+
}
455+
Predicate::Projection(proj_pred) => {
456+
let projection_ty = match self_ty.sty {
457+
ty::TyProjection(proj_ty) => proj_ty,
458+
_ => bug!("self_ty not projection for projection predicate.")
459+
};
460+
Predicate::Projection(ty::Binder(ty::ProjectionPredicate {
461+
projection_ty,
462+
ty: proj_pred.ty().skip_binder()
463+
}))
464+
}
465+
_ => bug!("Predicate {:?} not supported for type params.", pred)
466+
});
467+
}
468+
469+
predicates.predicates.extend(default_predicates);
470+
let predicates = predicates.instantiate_identity(fcx.tcx);
471+
let predicates = fcx.normalize_associated_types_in(span, &predicates);
472+
370473
let obligations =
371474
predicates.predicates
372475
.iter()
@@ -385,7 +488,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
385488
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
386489
span: Span,
387490
sig: ty::PolyFnSig<'tcx>,
388-
predicates: &ty::InstantiatedPredicates<'tcx>,
389491
def_id: DefId,
390492
implied_bounds: &mut Vec<Ty<'tcx>>)
391493
{
@@ -402,7 +504,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
402504
// FIXME(#25759) return types should not be implied bounds
403505
implied_bounds.push(sig.output());
404506

405-
self.check_where_clauses(fcx, span, predicates);
507+
self.check_where_clauses(fcx, span, def_id);
406508
}
407509

408510
fn check_method_receiver<'fcx, 'tcx>(&mut self,

src/test/run-pass/type-macros-simple.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ fn issue_36540() {
3434
}
3535

3636
trait Trait<T> {}
37+
impl Trait<i32> for i32 {}

src/test/ui/type-check-defaults.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
// compile-flags: --error-format=human
11+
12+
use std::iter::FromIterator;
13+
use std::vec::IntoIter;
14+
use std::ops::Add;
15+
16+
struct Foo<T, U: FromIterator<T>>(T, U);
17+
struct WellFormed<Z = Foo<i32, i32>>(Z);
18+
19+
struct WellFormedProjection<A, T=<A as Iterator>::Item>(A, T);
20+
21+
struct Bounds<T:Copy=String>(T);
22+
23+
struct WhereClause<T=String>(T) where T: Copy;
24+
25+
trait TraitBound<T:Copy=String> {}
26+
27+
trait SelfBound<T:Copy=Self> {}
28+
29+
trait FooTrait<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
30+
31+
fn main() { }
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
error[E0277]: the trait bound `i32: std::iter::FromIterator<i32>` is not satisfied
2+
--> $DIR/type-check-defaults.rs:17:1
3+
|
4+
17 | struct WellFormed<Z = Foo<i32, i32>>(Z);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a collection of type `i32` cannot be built from an iterator over elements of type `i32`
6+
|
7+
= help: the trait `std::iter::FromIterator<i32>` is not implemented for `i32`
8+
= note: required by `Foo`
9+
10+
error[E0277]: the trait bound `A: std::iter::Iterator` is not satisfied
11+
--> $DIR/type-check-defaults.rs:19:1
12+
|
13+
19 | struct WellFormedProjection<A, T=<A as Iterator>::Item>(A, T);
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `A` is not an iterator; maybe try calling `.iter()` or a similar method
15+
|
16+
= help: the trait `std::iter::Iterator` is not implemented for `A`
17+
= help: consider adding a `where A: std::iter::Iterator` bound
18+
19+
error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
20+
--> $DIR/type-check-defaults.rs:21:1
21+
|
22+
21 | struct Bounds<T:Copy=String>(T);
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
24+
|
25+
= note: required by `std::marker::Copy`
26+
27+
error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
28+
--> $DIR/type-check-defaults.rs:23:1
29+
|
30+
23 | struct WhereClause<T=String>(T) where T: Copy;
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
32+
|
33+
= note: required by `std::marker::Copy`
34+
35+
error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
36+
--> $DIR/type-check-defaults.rs:25:1
37+
|
38+
25 | trait TraitBound<T:Copy=String> {}
39+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
40+
|
41+
= note: required by `std::marker::Copy`
42+
43+
error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied
44+
--> $DIR/type-check-defaults.rs:27:1
45+
|
46+
27 | trait SelfBound<T:Copy=Self> {}
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Self`
48+
|
49+
= help: consider adding a `where Self: std::marker::Copy` bound
50+
= note: required by `std::marker::Copy`
51+
52+
error[E0277]: the trait bound `i32: std::ops::Add<u8>` is not satisfied
53+
--> $DIR/type-check-defaults.rs:29:1
54+
|
55+
29 | trait FooTrait<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
56+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8`
57+
|
58+
= help: the trait `std::ops::Add<u8>` is not implemented for `i32`
59+
= note: required by `std::ops::Add`
60+
61+
error: aborting due to 7 previous errors
62+

0 commit comments

Comments
 (0)