diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index 684b28d03739e..b5d19a66f322a 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -157,6 +157,12 @@ impl<'tcx> Substs<'tcx> {
                                   |r, m_regions| r.with_vec(FnSpace, m_regions));
         Substs { types: types, regions: regions }
     }
+
+    pub fn with_method_from(self, other: &Substs<'tcx>) -> Substs<'tcx> {
+        let types = other.types.get_slice(FnSpace).to_vec();
+        let regions = other.regions().get_slice(FnSpace).to_vec();
+        self.with_method(types, regions)
+    }
 }
 
 impl RegionSubsts {
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index a63dcfc24a10e..cf81af31bd519 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -413,10 +413,10 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi
     }
 }
 
-pub fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>,
-                                    cause: ObligationCause<'tcx>)
-                                    -> Result<ty::ParameterEnvironment<'a,'tcx>,
-                                              Vec<FulfillmentError<'tcx>>>
+fn normalize_param_env<'a,'tcx>(param_env: &ty::ParameterEnvironment<'a,'tcx>,
+                                cause: ObligationCause<'tcx>)
+                                -> Result<ty::ParameterEnvironment<'a,'tcx>,
+                                          Vec<FulfillmentError<'tcx>>>
 {
     let tcx = param_env.tcx;
 
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index 13f309e129ac9..9c8141817c40a 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -21,7 +21,7 @@ use super::VtableImplData;
 use super::util;
 
 use middle::infer;
-use middle::subst::{Subst, Substs};
+use middle::subst::Substs;
 use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape,
                  HasProjectionTypes, ToPolyTraitRef, Ty};
 use middle::ty_fold::{self, TypeFoldable, TypeFolder};
@@ -561,8 +561,7 @@ fn assemble_candidates_from_trait_def<'cx,'tcx>(
     };
 
     // If so, extract what we know from the trait and try to come up with a good answer.
-    let trait_predicates = ty::lookup_predicates(selcx.tcx(), trait_ref.def_id);
-    let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs);
+    let bounds = selcx.instantiate_trait_predicates(&trait_ref);
     assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
                                         candidate_set, bounds.predicates.into_vec());
 }
@@ -849,36 +848,38 @@ fn confirm_impl_candidate<'cx,'tcx>(
     impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>)
     -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
 {
+    let tcx = selcx.tcx();
     // there don't seem to be nicer accessors to these:
-    let impl_items_map = selcx.tcx().impl_items.borrow();
-    let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
+    let impl_items_map = tcx.impl_items.borrow();
+    let impl_or_trait_items_map = tcx.impl_or_trait_items.borrow();
 
     let impl_items = &impl_items_map[impl_vtable.impl_def_id];
-    let mut impl_ty = None;
-    for impl_item in impl_items {
-        let assoc_type = match impl_or_trait_items_map[impl_item.def_id()] {
-            ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
-            ty::MethodTraitItem(..) => { continue; }
-        };
-
-        if assoc_type.name != obligation.predicate.item_name {
-            continue;
-        }
-
-        let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
-        impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
-        break;
-    }
+    let assoc_type =
+        impl_items
+            .iter()
+            .filter_map(|item| {
+                match impl_or_trait_items_map[item.def_id()] {
+                    ty::TypeTraitItem(ref assoc_type)
+                    if assoc_type.name == obligation.predicate.item_name => {
+                        Some(assoc_type)
+                    }
+                    _ => None
+                }
+            })
+            .next();
 
-    match impl_ty {
-        Some(ty) => (ty, impl_vtable.nested.into_vec()),
+    match assoc_type {
+        Some(assoc_type) => {
+            let impl_ty = selcx.instantiate_assoc_type(assoc_type,
+                                                       &impl_vtable.substs);
+            (impl_ty, impl_vtable.nested.into_vec())
+        },
         None => {
-            // This means that the impl is missing a
-            // definition for the associated type. This error
-            // ought to be reported by the type checker method
-            // `check_impl_items_against_trait`, so here we
-            // just return ty_err.
-            (selcx.tcx().types.err, vec!())
+            // This means that the impl is missing a definition for the
+            // associated type. This error ought to be reported by the
+            // type checker method `check_impl_items_against_trait`, so
+            // here we just return ty_err.
+            (tcx.types.err, vec![])
         }
     }
 }
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 085758b44b5c7..165ad5955a3e8 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -33,14 +33,15 @@ use super::{util};
 
 use middle::fast_reject;
 use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace};
-use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
+use middle::ty::{self, AssociatedType, RegionEscape, ToPolyTraitRef, TraitRef, Ty};
 use middle::infer;
 use middle::infer::{InferCtxt, TypeFreshener};
 use middle::ty_fold::TypeFoldable;
 use std::cell::RefCell;
 use std::collections::hash_map::HashMap;
 use std::rc::Rc;
-use syntax::{abi, ast};
+use syntax::abi;
+use syntax::ast::{self, DefId};
 use util::common::ErrorReported;
 use util::ppaux::Repr;
 
@@ -2195,6 +2196,39 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ///////////////////////////////////////////////////////////////////////////
     // Miscellany
 
+    pub fn instantiate_assoc_type(&self,
+                                  assoc_ty: &AssociatedType,
+                                  impl_substs: &Substs<'tcx>)
+                                  -> Ty<'tcx>
+    {
+        let poly_ty = ty::lookup_item_type(self.tcx(), assoc_ty.def_id);
+        let substs = self.maybe_pick_free_substs(assoc_ty.container.id(), impl_substs);
+        poly_ty.ty.subst(self.tcx(), substs)
+    }
+
+    pub fn instantiate_trait_predicates(&self,
+                                        trait_ref: &Rc<TraitRef<'tcx>>)
+                                        -> ty::InstantiatedPredicates<'tcx>
+    {
+        let trait_predicates = ty::lookup_predicates(self.tcx(), trait_ref.def_id);
+        let substs = self.maybe_pick_free_substs(trait_ref.def_id, trait_ref.substs);
+        trait_predicates.instantiate(self.tcx(), substs)
+    }
+
+    fn maybe_pick_free_substs(&self,
+                              target_def_id: DefId,
+                              substs: &'cx Substs<'tcx>)
+                              -> &'cx Substs<'tcx>
+    {
+        // The free substitutions take precedence over the given one if
+        // current parameter environment is associated with `target_def_id`.
+        if self.param_env().def_id == target_def_id {
+            &self.param_env().free_substs
+        } else {
+            substs
+        }
+    }
+
     fn push_stack<'o,'s:'o>(&mut self,
                             previous_stack: Option<&'s TraitObligationStack<'s, 'tcx>>,
                             obligation: &'o TraitObligation<'tcx>)
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 1206424550f95..b45a31a159892 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -80,7 +80,7 @@ use std::vec::{CowVec, IntoIter};
 use collections::enum_set::{EnumSet, CLike};
 use std::collections::{HashMap, HashSet};
 use syntax::abi;
-use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE};
+use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, DUMMY_NODE_ID, LOCAL_CRATE};
 use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
 use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
 use syntax::ast_util::{self, is_local, lit_is_str, local_def, PostExpansionMethod};
@@ -2135,6 +2135,13 @@ impl<'tcx> TraitRef<'tcx> {
 pub struct ParameterEnvironment<'a, 'tcx:'a> {
     pub tcx: &'a ctxt<'tcx>,
 
+    /// Item the parameter environment is associated with. For `ItemImpl` or
+    /// `ItemFn`, this is the item itself; for `MethodImplItem`, however, this
+    /// is the implementation (container) it is in. A certain method may make
+    /// use of associated types, which are at the container level. So we need
+    /// to know this when instantiating associated types for methods.
+    pub def_id: DefId,
+
     /// See `construct_free_substs` for details.
     pub free_substs: Substs<'tcx>,
 
@@ -2161,6 +2168,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
     {
         ParameterEnvironment {
             tcx: self.tcx,
+            def_id: self.def_id,
             free_substs: self.free_substs.clone(),
             implicit_region_bound: self.implicit_region_bound,
             caller_bounds: caller_bounds,
@@ -2180,6 +2188,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                                 let method_bounds = &method_ty.predicates;
                                 construct_parameter_environment(
                                     cx,
+                                    method_ty.container.id(),
                                     method.span,
                                     method_generics,
                                     method_bounds,
@@ -2217,6 +2226,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                                 let method_bounds = &method_ty.predicates;
                                 construct_parameter_environment(
                                     cx,
+                                    method_ty.container.id(),
                                     method.span,
                                     method_generics,
                                     method_bounds,
@@ -2246,6 +2256,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                         let fn_predicates = lookup_predicates(cx, fn_def_id);
 
                         construct_parameter_environment(cx,
+                                                        fn_def_id,
                                                         item.span,
                                                         &fn_scheme.generics,
                                                         &fn_predicates,
@@ -2260,6 +2271,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                         let scheme = lookup_item_type(cx, def_id);
                         let predicates = lookup_predicates(cx, def_id);
                         construct_parameter_environment(cx,
+                                                        def_id,
                                                         item.span,
                                                         &scheme.generics,
                                                         &predicates,
@@ -4295,8 +4307,8 @@ pub fn ty_region(tcx: &ctxt,
     }
 }
 
-pub fn free_region_from_def(outlives_extent: region::DestructionScopeData,
-                            def: &RegionParameterDef)
+fn free_region_from_def(outlives_extent: region::DestructionScopeData,
+                        def: &RegionParameterDef)
     -> ty::Region
 {
     let ret =
@@ -5116,19 +5128,6 @@ pub fn is_associated_type(cx: &ctxt, id: ast::DefId) -> bool {
     })
 }
 
-/// Returns the parameter index that the given associated type corresponds to.
-pub fn associated_type_parameter_index(cx: &ctxt,
-                                       trait_def: &TraitDef,
-                                       associated_type_id: ast::DefId)
-                                       -> uint {
-    for type_parameter_def in trait_def.generics.types.iter() {
-        if type_parameter_def.def_id == associated_type_id {
-            return type_parameter_def.index as uint
-        }
-    }
-    cx.sess.bug("couldn't find associated type parameter index")
-}
-
 pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId)
                           -> Rc<Vec<ImplOrTraitItemId>> {
     lookup_locally_or_in_crate_store("trait_item_def_ids",
@@ -6318,6 +6317,7 @@ impl Variance {
 /// are no free type/lifetime parameters in scope.
 pub fn empty_parameter_environment<'a,'tcx>(cx: &'a ctxt<'tcx>) -> ParameterEnvironment<'a,'tcx> {
     ty::ParameterEnvironment { tcx: cx,
+                               def_id: local_def(DUMMY_NODE_ID),
                                free_substs: Substs::empty(),
                                caller_bounds: Vec::new(),
                                implicit_region_bound: ty::ReEmpty,
@@ -6355,7 +6355,7 @@ pub fn construct_free_substs<'a,'tcx>(
                           region_params: &[RegionParameterDef])
     {
         for r in region_params {
-            regions.push(r.space, ty::free_region_from_def(all_outlive_extent, r));
+            regions.push(r.space, free_region_from_def(all_outlive_extent, r));
         }
     }
 
@@ -6374,6 +6374,7 @@ pub fn construct_free_substs<'a,'tcx>(
 /// See `ParameterEnvironment` struct def'n for details
 pub fn construct_parameter_environment<'a,'tcx>(
     tcx: &'a ctxt<'tcx>,
+    def_id: DefId,
     span: Span,
     generics: &ty::Generics<'tcx>,
     generic_predicates: &ty::GenericPredicates<'tcx>,
@@ -6424,6 +6425,7 @@ pub fn construct_parameter_environment<'a,'tcx>(
 
     let unnormalized_env = ty::ParameterEnvironment {
         tcx: tcx,
+        def_id: def_id,
         free_substs: free_substs,
         implicit_region_bound: ty::ReScope(free_id_outlive.to_code_extent()),
         caller_bounds: predicates,
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 5e46ce08e4f76..ada0de16ffb49 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -575,18 +575,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
     }
 }
 
-impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where 'tcx: 'a {
-    fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ParameterEnvironment<'a, 'tcx> {
-        ty::ParameterEnvironment {
-            tcx: self.tcx,
-            free_substs: self.free_substs.fold_with(folder),
-            implicit_region_bound: self.implicit_region_bound.fold_with(folder),
-            caller_bounds: self.caller_bounds.fold_with(folder),
-            selection_cache: traits::SelectionCache::new(),
-        }
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // "super" routines: these are the default implementations for TypeFolder.
 //
diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs
index 377af080526b7..ee4676b8d25fa 100644
--- a/src/librustc_typeck/check/assoc.rs
+++ b/src/librustc_typeck/check/assoc.rs
@@ -29,7 +29,8 @@ pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
     debug!("normalize_associated_types_in(value={})", value.repr(infcx.tcx));
     let mut selcx = SelectionContext::new(infcx, typer);
     let cause = ObligationCause::new(span, body_id, MiscObligation);
-    let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value);
+    let Normalized { value: result,
+                     obligations } = traits::normalize(&mut selcx, cause, value);
     debug!("normalize_associated_types_in: result={} predicates={}",
            result.repr(infcx.tcx),
            obligations.repr(infcx.tcx));
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 1e1d7e0926038..598c44261b187 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -40,9 +40,6 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     debug!("compare_impl_method(impl_trait_ref={})",
            impl_trait_ref.repr(tcx));
 
-    debug!("compare_impl_method: impl_trait_ref (liberated) = {}",
-           impl_trait_ref.repr(tcx));
-
     let infcx = infer::new_infer_ctxt(tcx);
     let mut fulfillment_cx = traits::FulfillmentContext::new();
 
@@ -180,10 +177,8 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
 
     // Create mapping from trait to skolemized.
     let trait_to_skol_substs =
-        trait_to_impl_substs
-        .subst(tcx, impl_to_skol_substs)
-        .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
-                     impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
+        trait_to_impl_substs.subst(tcx, impl_to_skol_substs)
+                            .with_method_from(impl_to_skol_substs);
     debug!("compare_impl_method: trait_to_skol_substs={}",
            trait_to_skol_substs.repr(tcx));
 
@@ -208,10 +203,9 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
         impl_m.predicates.instantiate(tcx, impl_to_skol_substs);
 
     let (impl_bounds, _) =
-        infcx.replace_late_bound_regions_with_fresh_var(
-            impl_m_span,
-            infer::HigherRankedType,
-            &ty::Binder(impl_bounds));
+        infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
+                                                        infer::HigherRankedType,
+                                                        &ty::Binder(impl_bounds));
     debug!("compare_impl_method: impl_bounds={}",
            impl_bounds.repr(tcx));
 
@@ -243,7 +237,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     let trait_param_env = traits::normalize_param_env_or_error(trait_param_env,
                                                                normalize_cause.clone());
 
-    debug!("compare_impl_method: trait_bounds={}",
+    debug!("compare_impl_method: trait_param_env.caller_bounds={}",
         trait_param_env.caller_bounds.repr(tcx));
 
     let mut selcx = traits::SelectionContext::new(&infcx, &trait_param_env);
@@ -276,12 +270,6 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     // any associated types appearing in the fn arguments or return
     // type.
 
-    // Compute skolemized form of impl and trait method tys.
-    let impl_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(impl_m.fty.clone()));
-    let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs);
-    let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone()));
-    let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
-
     let err = infcx.try(|snapshot| {
         let origin = infer::MethodCompatCheck(impl_m_span);
 
@@ -336,9 +324,6 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     match err {
         Ok(()) => { }
         Err(terr) => {
-            debug!("checking trait method for compatibility: impl ty {}, trait ty {}",
-                   impl_fty.repr(tcx),
-                   trait_fty.repr(tcx));
             span_err!(tcx.sess, impl_m_span, E0053,
                       "method `{}` has an incompatible type for trait: {}",
                       token::get_name(trait_m.name),
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index b0ded25af1700..db16a29bab8e8 100644
--- a/src/librustc_typeck/check/wf.rs
+++ b/src/librustc_typeck/check/wf.rs
@@ -139,6 +139,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates);
         let param_env =
             ty::construct_parameter_environment(ccx.tcx,
+                                                item_def_id,
                                                 item.span,
                                                 &type_scheme.generics,
                                                 &type_predicates,
diff --git a/src/test/compile-fail/issue-22077.rs b/src/test/compile-fail/issue-22077.rs
new file mode 100644
index 0000000000000..9992068e67f1a
--- /dev/null
+++ b/src/test/compile-fail/issue-22077.rs
@@ -0,0 +1,26 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Fun {
+    type Output;
+    fn call<'x>(&'x self) -> Self::Output;
+}
+
+struct Holder { x: String }
+
+impl<'a> Fun for Holder {
+    type Output = &'a str;
+    fn call<'b>(&'b self) -> &'b str {
+    //~^ ERROR method `call` has an incompatible type for trait
+        &self.x[..]
+    }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/regions-assoc-type-region-bound-in-trait-not-met.rs b/src/test/compile-fail/regions-assoc-type-region-bound-in-trait-not-met.rs
index f921eccef1f8c..f1ed7b6e33dbf 100644
--- a/src/test/compile-fail/regions-assoc-type-region-bound-in-trait-not-met.rs
+++ b/src/test/compile-fail/regions-assoc-type-region-bound-in-trait-not-met.rs
@@ -22,12 +22,12 @@ impl<'a> Foo<'a> for &'a i16 {
 }
 
 impl<'a> Foo<'static> for &'a i32 {
-    //~^ ERROR cannot infer
+    //~^ ERROR does not fulfill the required lifetime
     type Value = &'a i32;
 }
 
 impl<'a,'b> Foo<'b> for &'a i64 {
-    //~^ ERROR cannot infer
+    //~^ ERROR does not fulfill the required lifetime
     type Value = &'a i32;
 }
 
diff --git a/src/test/compile-fail/regions-assoc-type-static-bound-in-trait-not-met.rs b/src/test/compile-fail/regions-assoc-type-static-bound-in-trait-not-met.rs
index 1cf83b8ac585f..7c371e3c15355 100644
--- a/src/test/compile-fail/regions-assoc-type-static-bound-in-trait-not-met.rs
+++ b/src/test/compile-fail/regions-assoc-type-static-bound-in-trait-not-met.rs
@@ -17,7 +17,7 @@ trait Foo {
 }
 
 impl<'a> Foo for &'a i32 {
-    //~^ ERROR cannot infer
+    //~^ ERROR does not fulfill the required lifetime
     type Value = &'a i32;
 }
 
diff --git a/src/test/run-pass/issue-21750.rs b/src/test/run-pass/issue-21750.rs
new file mode 100644
index 0000000000000..7c039a14f4801
--- /dev/null
+++ b/src/test/run-pass/issue-21750.rs
@@ -0,0 +1,36 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Arg<A> {
+    fn arg(&self) -> A;
+}
+
+pub trait Traversal {
+    type Item;
+    fn foreach<F: Arg<Self::Item>>(F);
+}
+
+impl<'a> Traversal for i32 {
+    type Item = &'a i32;
+    fn foreach<F: Arg<&'a i32>>(f: F) {
+        f.arg();
+    }
+}
+
+impl<'a> Traversal for u8 {
+    type Item = &'a u8;
+    // A more verbose way to refer to the associated type. Should also work
+    // nonetheless.
+    fn foreach<F: Arg<<Self as Traversal>::Item>>(f: F) {
+        let _ = f.arg();
+    }
+}
+
+fn main() {}
diff --git a/src/test/run-pass/issue-22066.rs b/src/test/run-pass/issue-22066.rs
new file mode 100644
index 0000000000000..2efcfc3a756e4
--- /dev/null
+++ b/src/test/run-pass/issue-22066.rs
@@ -0,0 +1,22 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait LineFormatter<'a> {
+    type Iter: Iterator<Item=&'a str> + 'a;
+    fn iter(&'a self, line: &'a str) -> Self::Iter;
+
+    fn dimensions(&'a self, line: &'a str) {
+        for grapheme in self.iter(line) {
+            let _ = grapheme.len();
+        }
+    }
+}
+
+fn main() {}