@@ -35,7 +35,7 @@ use middle::lang_items::SizedTraitLangItem;
35
35
use middle:: region;
36
36
use middle:: resolve_lifetime;
37
37
use middle:: subst;
38
- use middle:: subst:: { Substs } ;
38
+ use middle:: subst:: { Substs , TypeSpace } ;
39
39
use middle:: ty:: { AsPredicate , ImplContainer , ImplOrTraitItemContainer , TraitContainer } ;
40
40
use middle:: ty:: { self , RegionEscape , Ty , TypeScheme } ;
41
41
use middle:: ty_fold:: { self , TypeFolder , TypeFoldable } ;
@@ -47,6 +47,7 @@ use util::ppaux;
47
47
use util:: ppaux:: { Repr , UserString } ;
48
48
use write_ty_to_tcx;
49
49
50
+ use std:: collections:: HashSet ;
50
51
use std:: rc:: Rc ;
51
52
52
53
use syntax:: abi;
@@ -644,6 +645,10 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) {
644
645
Some ( selfty) ,
645
646
None ) ;
646
647
}
648
+
649
+ enforce_impl_ty_params_are_constrained ( ccx. tcx ,
650
+ generics,
651
+ local_def ( it. id ) ) ;
647
652
} ,
648
653
ast:: ItemTrait ( _, _, _, ref trait_methods) => {
649
654
let trait_def = trait_def_of_item ( ccx, it) ;
@@ -1605,3 +1610,96 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
1605
1610
} )
1606
1611
}
1607
1612
}
1613
+
1614
+ /// Checks that all the type parameters on an impl
1615
+ fn enforce_impl_ty_params_are_constrained < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
1616
+ ast_generics : & ast:: Generics ,
1617
+ impl_def_id : ast:: DefId )
1618
+ {
1619
+ let impl_scheme = ty:: lookup_item_type ( tcx, impl_def_id) ;
1620
+ let impl_trait_ref = ty:: impl_trait_ref ( tcx, impl_def_id) ;
1621
+
1622
+ // The trait reference is an input, so find all type parameters
1623
+ // reachable from there, to start (if this is an inherent impl,
1624
+ // then just examine the self type).
1625
+ let mut input_parameters: HashSet < _ > =
1626
+ impl_trait_ref. iter ( )
1627
+ . flat_map ( |t| t. input_types ( ) . iter ( ) ) // Types in trait ref, if any
1628
+ . chain ( Some ( impl_scheme. ty ) . iter ( ) ) // Self type, always
1629
+ . flat_map ( |t| t. walk ( ) )
1630
+ . filter_map ( to_opt_param_ty)
1631
+ . collect ( ) ;
1632
+
1633
+ loop {
1634
+ let num_inputs = input_parameters. len ( ) ;
1635
+
1636
+ let mut projection_predicates =
1637
+ impl_scheme. generics . predicates
1638
+ . iter ( )
1639
+ . filter_map ( |predicate| {
1640
+ match * predicate {
1641
+ // Ignore higher-ranked binders. For the purposes
1642
+ // of this check, they don't matter because they
1643
+ // only affect named regions, and we're just
1644
+ // concerned about type parameters here.
1645
+ ty:: Predicate :: Projection ( ref data) => Some ( data. 0 . clone ( ) ) ,
1646
+ _ => None ,
1647
+ }
1648
+ } ) ;
1649
+
1650
+ for projection in projection_predicates {
1651
+ // Special case: watch out for some kind of sneaky attempt
1652
+ // to project out an associated type defined by this very trait.
1653
+ if Some ( projection. projection_ty . trait_ref . clone ( ) ) == impl_trait_ref {
1654
+ continue ;
1655
+ }
1656
+
1657
+ let relies_only_on_inputs =
1658
+ projection. projection_ty . trait_ref . input_types ( ) . iter ( )
1659
+ . flat_map ( |t| t. walk ( ) )
1660
+ . filter_map ( to_opt_param_ty)
1661
+ . all ( |t| input_parameters. contains ( & t) ) ;
1662
+
1663
+ if relies_only_on_inputs {
1664
+ input_parameters. extend (
1665
+ projection. ty . walk ( ) . filter_map ( to_opt_param_ty) ) ;
1666
+ }
1667
+ }
1668
+
1669
+ if input_parameters. len ( ) == num_inputs {
1670
+ break ;
1671
+ }
1672
+ }
1673
+
1674
+ for ( index, ty_param) in ast_generics. ty_params . iter ( ) . enumerate ( ) {
1675
+ let param_ty = ty:: ParamTy { space : TypeSpace ,
1676
+ idx : index as u32 ,
1677
+ name : ty_param. ident . name } ;
1678
+ if !input_parameters. contains ( & param_ty) {
1679
+ if ty:: has_attr ( tcx, impl_def_id, "old_impl_check" ) {
1680
+ tcx. sess . span_warn (
1681
+ ty_param. span ,
1682
+ format ! ( "the type parameter `{}` is not constrained by the \
1683
+ impl trait, self type, or predicates",
1684
+ param_ty. user_string( tcx) ) . as_slice ( ) ) ;
1685
+ } else {
1686
+ tcx. sess . span_err (
1687
+ ty_param. span ,
1688
+ format ! ( "the type parameter `{}` is not constrained by the \
1689
+ impl trait, self type, or predicates",
1690
+ param_ty. user_string( tcx) ) . as_slice ( ) ) ;
1691
+ tcx. sess . span_help (
1692
+ ty_param. span ,
1693
+ format ! ( "you can temporarily opt out of this rule by placing \
1694
+ the `#[old_impl_check]` attribute on the impl") . as_slice ( ) ) ;
1695
+ }
1696
+ }
1697
+ }
1698
+
1699
+ fn to_opt_param_ty < ' tcx > ( ty : Ty < ' tcx > ) -> Option < ty:: ParamTy > {
1700
+ match ty. sty {
1701
+ ty:: ty_param( ref d) => Some ( d. clone ( ) ) ,
1702
+ _ => None ,
1703
+ }
1704
+ }
1705
+ }
0 commit comments