@@ -35,7 +35,7 @@ use middle::lang_items::SizedTraitLangItem;
3535use middle:: region;
3636use middle:: resolve_lifetime;
3737use middle:: subst;
38- use middle:: subst:: { Substs } ;
38+ use middle:: subst:: { Substs , TypeSpace } ;
3939use middle:: ty:: { AsPredicate , ImplContainer , ImplOrTraitItemContainer , TraitContainer } ;
4040use middle:: ty:: { self , RegionEscape , Ty , TypeScheme } ;
4141use middle:: ty_fold:: { self , TypeFolder , TypeFoldable } ;
@@ -47,6 +47,7 @@ use util::ppaux;
4747use util:: ppaux:: { Repr , UserString } ;
4848use write_ty_to_tcx;
4949
50+ use std:: collections:: HashSet ;
5051use std:: rc:: Rc ;
5152
5253use syntax:: abi;
@@ -644,6 +645,10 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) {
644645 Some ( selfty) ,
645646 None ) ;
646647 }
648+
649+ enforce_impl_ty_params_are_constrained ( ccx. tcx ,
650+ generics,
651+ local_def ( it. id ) ) ;
647652 } ,
648653 ast:: ItemTrait ( _, _, _, ref trait_methods) => {
649654 let trait_def = trait_def_of_item ( ccx, it) ;
@@ -1605,3 +1610,96 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
16051610 } )
16061611 }
16071612}
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