Skip to content

Commit cb9da17

Browse files
committed
Type check defaults.
And refactor duplicated code.
1 parent 53a6d14 commit cb9da17

File tree

4 files changed

+217
-22
lines changed

4 files changed

+217
-22
lines changed

src/librustc_typeck/check/wfcheck.rs

+123-22
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
180180
reject_shadowing_type_parameters(fcx.tcx, item.def_id);
181181
let sig = fcx.tcx.fn_sig(item.def_id);
182182
let sig = fcx.normalize_associated_types_in(span, &sig);
183-
let predicates = fcx.tcx.predicates_of(item.def_id)
184-
.instantiate_identity(fcx.tcx);
185-
let predicates = fcx.normalize_associated_types_in(span, &predicates);
186-
this.check_fn_or_method(fcx, span, sig, &predicates,
183+
this.check_fn_or_method(fcx, span, sig,
187184
item.def_id, &mut implied_bounds);
188185
let sig_if_method = sig_if_method.expect("bad signature for method");
189186
this.check_method_receiver(fcx, sig_if_method, &item, self_ty);
@@ -267,9 +264,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
267264
}
268265
}
269266

270-
let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
271-
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
272-
this.check_where_clauses(fcx, item.span, &predicates);
267+
self.check_where_clauses(fcx, item.span, def_id);
273268

274269
vec![] // no implied bounds in a struct def'n
275270
});
@@ -343,10 +338,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
343338
self.check_auto_trait(trait_def_id, item.span);
344339
}
345340

346-
self.for_item(item).with_fcx(|fcx, this| {
347-
let predicates = fcx.tcx.predicates_of(trait_def_id).instantiate_identity(fcx.tcx);
348-
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
349-
this.check_where_clauses(fcx, item.span, &predicates);
341+
self.for_item(item).with_fcx(|fcx, _| {
342+
self.check_where_clauses(fcx, item.span, trait_def_id);
350343
vec![]
351344
});
352345
}
@@ -356,12 +349,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
356349
let def_id = fcx.tcx.hir.local_def_id(item.id);
357350
let sig = fcx.tcx.fn_sig(def_id);
358351
let sig = fcx.normalize_associated_types_in(item.span, &sig);
359-
360-
let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
361-
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
362-
363352
let mut implied_bounds = vec![];
364-
this.check_fn_or_method(fcx, item.span, sig, &predicates,
353+
this.check_fn_or_method(fcx, item.span, sig,
365354
def_id, &mut implied_bounds);
366355
implied_bounds
367356
})
@@ -415,19 +404,132 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
415404
}
416405
}
417406

418-
let predicates = fcx.tcx.predicates_of(item_def_id).instantiate_identity(fcx.tcx);
419-
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
420-
this.check_where_clauses(fcx, item.span, &predicates);
407+
this.check_where_clauses(fcx, item.span, item_def_id);
421408

422409
fcx.impl_implied_bounds(item_def_id, item.span)
423410
});
424411
}
425412

413+
/// Checks where clauses and inline bounds.
426414
fn check_where_clauses<'fcx, 'tcx>(&mut self,
427415
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
428416
span: Span,
429-
predicates: &ty::InstantiatedPredicates<'tcx>)
417+
def_id: DefId)
430418
{
419+
use ty::subst::Subst;
420+
use ty::Predicate;
421+
422+
// Check that each default fulfills the bounds on it's parameter.
423+
// We go over each predicate and duplicate it, substituting defaults in the self type.
424+
let mut predicates = fcx.tcx.predicates_of(def_id);
425+
let mut default_predicates = Vec::new();
426+
for pred in &predicates.predicates {
427+
let mut self_ty = match pred {
428+
Predicate::Trait(trait_pred) => trait_pred.skip_binder().self_ty(),
429+
Predicate::TypeOutlives(outlives_pred) => (outlives_pred.0).0,
430+
Predicate::Projection(proj_pred) => {
431+
fcx.tcx.mk_ty(ty::TyProjection(proj_pred.skip_binder().projection_ty))
432+
}
433+
// Lifetime params can't have defaults.
434+
Predicate::RegionOutlives(..) => continue,
435+
_ => bug!("Predicate {:?} not supported in where clauses.", pred)
436+
};
437+
438+
let mut skip = false;
439+
let mut no_default = true;
440+
let generics = self.tcx.generics_of(def_id);
441+
let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
442+
// All regions are identity.
443+
fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
444+
}, |def, _| {
445+
// No default or generic comes from parent, identity substitution.
446+
if !def.has_default || (def.index as usize) < generics.parent_count() {
447+
fcx.tcx.mk_param_from_def(def)
448+
} else {
449+
no_default = false;
450+
// Has a default, use it in the substitution.
451+
let default_ty = fcx.tcx.type_of(def.def_id);
452+
// Skip `Self : Self` in traits, it's problematic.
453+
// This means we probably check less than we could.
454+
let should_skip = match self_ty.sty {
455+
ty::TyParam(ref p) => {
456+
// lhs is Self && rhs is Self
457+
p.is_self() && match pred {
458+
Predicate::Trait(p) => p.def_id() == def_id,
459+
Predicate::TypeOutlives(_) => false,
460+
_ => bug!("Unexpected predicate {:?}", pred)
461+
}
462+
}
463+
ty::TyProjection(ref proj) => {
464+
let mut projection = proj;
465+
let mut next_typ = &projection.substs[0].as_type().unwrap().sty;
466+
// Dig through projections.
467+
while let ty::TyProjection(ref proj) = next_typ {
468+
projection = proj;
469+
next_typ = &projection.substs[0].as_type().unwrap().sty;
470+
}
471+
let lhs_is_self = match next_typ {
472+
ty::TyParam(ref p) => p.is_self(),
473+
_ => false
474+
};
475+
let rhs = fcx.tcx.associated_item(projection.item_def_id)
476+
.container
477+
.assert_trait();
478+
lhs_is_self && rhs == def_id
479+
}
480+
_ => false
481+
};
482+
skip = skip || should_skip;
483+
484+
match default_ty.sty {
485+
// Skip `Self: Sized` when `Self` is the default. Needed in traits.
486+
ty::TyParam(ref p) if p.is_self() => {
487+
if let Predicate::Trait(p) = pred {
488+
if Some(p.def_id()) == fcx.tcx.lang_items().sized_trait() {
489+
skip = true;
490+
}
491+
}
492+
}
493+
_ => ()
494+
}
495+
default_ty
496+
}
497+
});
498+
499+
if skip || no_default {
500+
continue;
501+
}
502+
503+
self_ty = self_ty.subst(fcx.tcx, substs);
504+
default_predicates.push(match pred {
505+
Predicate::Trait(trait_pred) => {
506+
let mut substs = trait_pred.skip_binder().trait_ref.substs.to_vec();
507+
substs[0] = self_ty.into();
508+
let substs = fcx.tcx.intern_substs(&substs);
509+
let trait_ref = ty::Binder(ty::TraitRef::new(trait_pred.def_id(), substs));
510+
Predicate::Trait(trait_ref.to_poly_trait_predicate())
511+
}
512+
Predicate::TypeOutlives(pred) => {
513+
Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(self_ty, (pred.0).1)))
514+
}
515+
Predicate::Projection(proj_pred) => {
516+
let projection_ty = match self_ty.sty {
517+
ty::TyProjection(proj_ty) => proj_ty,
518+
_ => bug!("self_ty not projection for projection predicate.")
519+
};
520+
Predicate::Projection(ty::Binder(ty::ProjectionPredicate {
521+
projection_ty,
522+
ty: proj_pred.ty().skip_binder()
523+
}))
524+
}
525+
_ => bug!("Predicate {:?} not supported for type params.", pred)
526+
});
527+
}
528+
529+
predicates.predicates.extend(default_predicates);
530+
let predicates = predicates.instantiate_identity(fcx.tcx);
531+
let predicates = fcx.normalize_associated_types_in(span, &predicates);
532+
431533
let obligations =
432534
predicates.predicates
433535
.iter()
@@ -446,7 +548,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
446548
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
447549
span: Span,
448550
sig: ty::PolyFnSig<'tcx>,
449-
predicates: &ty::InstantiatedPredicates<'tcx>,
450551
def_id: DefId,
451552
implied_bounds: &mut Vec<Ty<'tcx>>)
452553
{
@@ -463,7 +564,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
463564
// FIXME(#25759) return types should not be implied bounds
464565
implied_bounds.push(sig.output());
465566

466-
self.check_where_clauses(fcx, span, predicates);
567+
self.check_where_clauses(fcx, span, def_id);
467568
}
468569

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

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

+1
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

+31
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() { }
+62
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)