about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-03-01 01:30:41 +0200
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-03-01 16:56:08 +0200
commitca8708273b6d7ee506e7d03051778d520cfaa50f (patch)
treebbb57f2ee8730d1f634dbfef28844846423e7930
parente1cb9ba221e5cb0070ac82c6a234af11e4240680 (diff)
downloadrust-ca8708273b6d7ee506e7d03051778d520cfaa50f.tar.gz
rust-ca8708273b6d7ee506e7d03051778d520cfaa50f.zip
more through normalization in typeck & trans
Fixes #27901.
Fixes #28828.
Fixes #38135.
Fixes #39363.
-rw-r--r--src/librustc_trans/base.rs9
-rw-r--r--src/librustc_trans/callee.rs18
-rw-r--r--src/librustc_trans/collector.rs11
-rw-r--r--src/librustc_trans/common.rs12
-rw-r--r--src/librustc_trans/consts.rs9
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs9
-rw-r--r--src/librustc_trans/debuginfo/mod.rs11
-rw-r--r--src/librustc_trans/partitioning.rs9
-rw-r--r--src/librustc_trans/trans_item.rs9
-rw-r--r--src/librustc_typeck/astconv.rs24
-rw-r--r--src/librustc_typeck/check/mod.rs50
-rw-r--r--src/librustc_typeck/collect.rs13
-rw-r--r--src/test/run-pass/issue-27901.rs20
-rw-r--r--src/test/run-pass/issue-28828.rs27
14 files changed, 121 insertions, 110 deletions
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 8125f432ff5..36f6fa76439 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -596,10 +596,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
     // release builds.
     info!("trans_instance({})", instance);
 
-    let fn_ty = ccx.tcx().item_type(instance.def);
-    let fn_ty = ccx.tcx().erase_regions(&fn_ty);
-    let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
-
+    let fn_ty = common::def_ty(ccx.shared(), instance.def, instance.substs);
     let sig = common::ty_fn_sig(ccx, fn_ty);
     let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
 
@@ -626,9 +623,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     attributes::inline(llfn, attributes::InlineAttr::Hint);
     attributes::set_frame_pointer_elimination(ccx, llfn);
 
-    let ctor_ty = ccx.tcx().item_type(def_id);
-    let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);
-
+    let ctor_ty = common::def_ty(ccx.shared(), def_id, substs);
     let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig());
     let fn_ty = FnType::new(ccx, sig, &[]);
 
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 4925c9d547e..762aaf1ce1d 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -24,14 +24,15 @@ use abi::{Abi, FnType};
 use attributes;
 use base;
 use builder::Builder;
-use common::{self, CrateContext, SharedCrateContext};
+use common::{self, CrateContext};
 use cleanup::CleanupScope;
 use mir::lvalue::LvalueRef;
 use consts;
+use common::def_ty;
 use declare;
 use value::Value;
 use meth;
-use monomorphize::{self, Instance};
+use monomorphize::Instance;
 use trans_item::TransItem;
 use type_of;
 use Disr;
@@ -207,16 +208,6 @@ impl<'tcx> Callee<'tcx> {
     }
 }
 
-/// Given a DefId and some Substs, produces the monomorphic item type.
-fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
-                    def_id: DefId,
-                    substs: &'tcx Substs<'tcx>)
-                    -> Ty<'tcx> {
-    let ty = shared.tcx().item_type(def_id);
-    monomorphize::apply_param_substs(shared, substs, &ty)
-}
-
-
 fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
                                   def_id: DefId,
                                   substs: ty::ClosureSubsts<'tcx>,
@@ -544,8 +535,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     let substs = tcx.normalize_associated_type(&substs);
     let instance = Instance::new(def_id, substs);
-    let item_ty = ccx.tcx().item_type(def_id);
-    let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty);
+    let fn_ty = common::def_ty(ccx.shared(), def_id, substs);
 
     if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
         return (llfn, fn_ty);
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index b12c1220b2b..7e349c6d0cb 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -207,7 +207,7 @@ use syntax_pos::DUMMY_SP;
 use base::custom_coerce_unsize_info;
 use callee::needs_fn_once_adapter_shim;
 use context::SharedCrateContext;
-use common::fulfill_obligation;
+use common::{def_ty, fulfill_obligation};
 use glue::{self, DropGlueKind};
 use monomorphize::{self, Instance};
 use util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
@@ -341,7 +341,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
             // Sanity check whether this ended up being collected accidentally
             debug_assert!(should_trans_locally(scx.tcx(), def_id));
 
-            let ty = scx.tcx().item_type(def_id);
+            let ty = def_ty(scx, def_id, Substs::empty());
             let ty = glue::get_drop_glue_type(scx, ty);
             neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
 
@@ -815,10 +815,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
         }
         ty::TyAdt(def, substs) => {
             for field in def.all_fields() {
-                let field_type = scx.tcx().item_type(field.did);
-                let field_type = monomorphize::apply_param_substs(scx,
-                                                                  substs,
-                                                                  &field_type);
+                let field_type = def_ty(scx, field.did, substs);
                 let field_type = glue::get_drop_glue_type(scx, field_type);
 
                 if scx.type_needs_drop(field_type) {
@@ -1184,7 +1181,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
                         debug!("RootCollector: ADT drop-glue for {}",
                                def_id_to_string(self.scx.tcx(), def_id));
 
-                        let ty = self.scx.tcx().item_type(def_id);
+                        let ty = def_ty(self.scx, def_id, Substs::empty());
                         let ty = glue::get_drop_glue_type(self.scx, ty);
                         self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
                     }
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 1032da7ef75..a509587f80f 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -29,7 +29,7 @@ use type_::Type;
 use value::Value;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::Layout;
-use rustc::ty::subst::Subst;
+use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::{self, SelectionContext, Reveal};
 use rustc::hir;
 
@@ -604,3 +604,13 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 pub fn is_closure(tcx: TyCtxt, def_id: DefId) -> bool {
     tcx.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr
 }
+
+/// Given a DefId and some Substs, produces the monomorphic item type.
+pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
+                        def_id: DefId,
+                        substs: &'tcx Substs<'tcx>)
+                        -> Ty<'tcx>
+{
+    let ty = shared.tcx().item_type(def_id);
+    monomorphize::apply_param_substs(shared, substs, &ty)
+}
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 011f7748f2c..bf1d9886ae7 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -18,12 +18,13 @@ use rustc::hir::map as hir_map;
 use {debuginfo, machine};
 use base;
 use trans_item::TransItem;
-use common::{CrateContext, val_ty};
+use common::{self, CrateContext, val_ty};
 use declare;
-use monomorphize::{Instance};
+use monomorphize::Instance;
 use type_::Type;
 use type_of;
 use rustc::ty;
+use rustc::ty::subst::Substs;
 
 use rustc::hir;
 
@@ -84,7 +85,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
         return g;
     }
 
-    let ty = ccx.tcx().item_type(def_id);
+    let ty = common::def_ty(ccx.shared(), def_id, Substs::empty());
     let g = if let Some(id) = ccx.tcx().hir.as_local_node_id(def_id) {
 
         let llty = type_of::type_of(ccx, ty);
@@ -234,7 +235,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             v
         };
 
-        let ty = ccx.tcx().item_type(def_id);
+        let ty = common::def_ty(ccx.shared(), def_id, Substs::empty());
         let llty = type_of::type_of(ccx, ty);
         let g = if val_llty == llty {
             g
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index f6cdd883850..049178a2575 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -33,7 +33,7 @@ use rustc::ty::util::TypeIdHasher;
 use rustc::hir;
 use rustc_data_structures::ToHex;
 use {type_of, machine, monomorphize};
-use common::CrateContext;
+use common::{self, CrateContext};
 use type_::Type;
 use rustc::ty::{self, AdtKind, Ty, layout};
 use session::config;
@@ -377,7 +377,7 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                       span: Span)
                                       -> MetadataCreationResult
 {
-    let signature = cx.tcx().erase_late_bound_regions(&signature);
+    let signature = cx.tcx().erase_late_bound_regions_and_normalize(&signature);
 
     let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs().len() + 1);
 
@@ -1764,7 +1764,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
     };
 
     let is_local_to_unit = is_node_local_to_unit(cx, node_id);
-    let variable_type = tcx.erase_regions(&tcx.item_type(node_def_id));
+    let variable_type = common::def_ty(cx.shared(), node_def_id, Substs::empty());
     let type_metadata = type_metadata(cx, variable_type, span);
     let var_name = tcx.item_name(node_def_id).to_string();
     let linkage_name = mangled_name_of_item(cx, node_def_id, "");
@@ -1772,8 +1772,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
     let var_name = CString::new(var_name).unwrap();
     let linkage_name = CString::new(linkage_name).unwrap();
 
-    let ty = cx.tcx().item_type(node_def_id);
-    let global_align = type_of::align_of(cx, ty);
+    let global_align = type_of::align_of(cx, variable_type);
 
     unsafe {
         llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx),
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index d5f04542d02..6933f158256 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -27,9 +27,9 @@ use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 
 use abi::Abi;
-use common::CrateContext;
+use common::{self, CrateContext};
 use builder::Builder;
-use monomorphize::{self, Instance};
+use monomorphize::Instance;
 use rustc::ty::{self, Ty};
 use rustc::mir;
 use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
@@ -397,11 +397,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         let self_type = cx.tcx().impl_of_method(instance.def).and_then(|impl_def_id| {
             // If the method does *not* belong to a trait, proceed
             if cx.tcx().trait_id_of_impl(impl_def_id).is_none() {
-                let impl_self_ty = cx.tcx().item_type(impl_def_id);
-                let impl_self_ty = cx.tcx().erase_regions(&impl_self_ty);
-                let impl_self_ty = monomorphize::apply_param_substs(cx.shared(),
-                                                                    instance.substs,
-                                                                    &impl_self_ty);
+                let impl_self_ty =
+                    common::def_ty(cx.shared(), impl_def_id, instance.substs);
 
                 // Only "class" methods are generally understood by LLVM,
                 // so avoid methods on other types (e.g. `<*mut T>::null`).
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index 706f131ed62..cc9fd8f46f6 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -103,9 +103,9 @@
 //! inlining, even when they are not marked #[inline].
 
 use collector::InliningMap;
+use common;
 use context::SharedCrateContext;
 use llvm;
-use monomorphize;
 use rustc::dep_graph::{DepNode, WorkProductId};
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
@@ -468,12 +468,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't
             if let Some(impl_def_id) = tcx.impl_of_method(instance.def) {
                 // This is a method within an inherent impl, find out what the
                 // self-type is:
-                let impl_self_ty = tcx.item_type(impl_def_id);
-                let impl_self_ty = tcx.erase_regions(&impl_self_ty);
-                let impl_self_ty = monomorphize::apply_param_substs(scx,
-                                                                    instance.substs,
-                                                                    &impl_self_ty);
-
+                let impl_self_ty = common::def_ty(scx, impl_def_id, instance.substs);
                 if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
                     return Some(def_id);
                 }
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index d691fa6aadf..d19f04b9554 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -22,7 +22,7 @@ use common;
 use declare;
 use glue::DropGlueKind;
 use llvm;
-use monomorphize::{self, Instance};
+use monomorphize::Instance;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
@@ -146,7 +146,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
                         linkage: llvm::Linkage,
                         symbol_name: &str) {
         let def_id = ccx.tcx().hir.local_def_id(node_id);
-        let ty = ccx.tcx().item_type(def_id);
+        let ty = common::def_ty(ccx.shared(), def_id, Substs::empty());
         let llty = type_of::type_of(ccx, ty);
 
         let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| {
@@ -168,10 +168,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
         assert!(!instance.substs.needs_infer() &&
                 !instance.substs.has_param_types());
 
-        let item_ty = ccx.tcx().item_type(instance.def);
-        let item_ty = ccx.tcx().erase_regions(&item_ty);
-        let mono_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &item_ty);
-
+        let mono_ty = common::def_ty(ccx.shared(), instance.def, instance.substs);
         let attrs = ccx.tcx().get_attrs(instance.def);
         let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty);
         unsafe { llvm::LLVMRustSetLinkage(lldecl, linkage) };
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 577fe31eab0..923ec05c22b 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -79,13 +79,8 @@ pub trait AstConv<'gcx, 'tcx> {
                                         item_name: ast::Name)
                                         -> Ty<'tcx>;
 
-    /// Project an associated type from a non-higher-ranked trait reference.
-    /// This is fairly straightforward and can be accommodated in any context.
-    fn projected_ty(&self,
-                    span: Span,
-                    _trait_ref: ty::TraitRef<'tcx>,
-                    _item_name: ast::Name)
-                    -> Ty<'tcx>;
+    /// Normalize an associated type coming from the user.
+    fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
 
     /// Invoked when we encounter an error from some prior pass
     /// (e.g. resolve) that is translated into a ty-error. This is
@@ -310,8 +305,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     tcx.types.err
                 } else {
                     // This is a default type parameter.
-                    ty::queries::ty::get(tcx, span, def.def_id)
-                        .subst_spanned(tcx, substs, Some(span))
+                    self.normalize_ty(
+                        span,
+                        ty::queries::ty::get(tcx, span, def.def_id)
+                            .subst_spanned(tcx, substs, Some(span))
+                    )
                 }
             } else {
                 // We've already errored above about the mismatch.
@@ -600,7 +598,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         -> Ty<'tcx>
     {
         let substs = self.ast_path_substs_for_ty(span, did, item_segment);
-        ty::queries::ty::get(self.tcx(), span, did).subst(self.tcx(), substs)
+        self.normalize_ty(
+            span,
+            ty::queries::ty::get(self.tcx(), span, did).subst(self.tcx(), substs)
+        )
     }
 
     /// Transform a PolyTraitRef into a PolyExistentialTraitRef by
@@ -900,6 +901,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         let trait_did = bound.0.def_id;
         let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
+        let ty = self.normalize_ty(span, ty);
 
         let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name);
         let def_id = item.expect("missing associated type").def_id;
@@ -939,7 +941,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
 
-        self.projected_ty(span, trait_ref, item_segment.name)
+        self.normalize_ty(span, tcx.mk_projection(trait_ref, item_segment.name))
     }
 
     pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0337727dcba..c3271914768 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -739,8 +739,9 @@ fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             check_fn(&inh, fn_sig, decl, id, body)
         } else {
-            let expected_type = tcx.item_type(def_id);
             let fcx = FnCtxt::new(&inh, None, body.value.id);
+            let expected_type = tcx.item_type(def_id);
+            let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
             fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
 
             // Gather locals in statics (because of block expressions).
@@ -1442,16 +1443,15 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
                 infer::LateBoundRegionConversionTime::AssocTypeProjection(item_name),
                 &poly_trait_ref);
 
-        self.normalize_associated_type(span, trait_ref, item_name)
+        self.tcx().mk_projection(trait_ref, item_name)
     }
 
-    fn projected_ty(&self,
-                    span: Span,
-                    trait_ref: ty::TraitRef<'tcx>,
-                    item_name: ast::Name)
-                    -> Ty<'tcx>
-    {
-        self.normalize_associated_type(span, trait_ref, item_name)
+    fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if ty.has_escaping_regions() {
+            ty // FIXME: normalization and escaping regions
+        } else {
+            self.normalize_associated_types_in(span, &ty)
+        }
     }
 
     fn set_tainted_by_errors(&self) {
@@ -1728,25 +1728,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.inh.normalize_associated_types_in(span, self.body_id, value)
     }
 
-    fn normalize_associated_type(&self,
-                                 span: Span,
-                                 trait_ref: ty::TraitRef<'tcx>,
-                                 item_name: ast::Name)
-                                 -> Ty<'tcx>
-    {
-        let cause = traits::ObligationCause::new(span,
-                                                 self.body_id,
-                                                 traits::ObligationCauseCode::MiscObligation);
-        self.fulfillment_cx
-            .borrow_mut()
-            .normalize_projection_type(self,
-                                       ty::ProjectionTy {
-                                           trait_ref: trait_ref,
-                                           item_name: item_name,
-                                       },
-                                       cause)
-    }
-
     pub fn write_nil(&self, node_id: ast::NodeId) {
         self.write_ty(node_id, self.tcx.mk_nil());
     }
@@ -1777,9 +1758,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn register_bound(&self,
-                                  ty: Ty<'tcx>,
-                                  def_id: DefId,
-                                  cause: traits::ObligationCause<'tcx>)
+                          ty: Ty<'tcx>,
+                          def_id: DefId,
+                          cause: traits::ObligationCause<'tcx>)
     {
         self.fulfillment_cx.borrow_mut()
             .register_bound(self, ty, def_id, cause);
@@ -1788,8 +1769,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn register_predicate(&self,
                               obligation: traits::PredicateObligation<'tcx>)
     {
-        debug!("register_predicate({:?})",
-               obligation);
+        debug!("register_predicate({:?})", obligation);
+        if obligation.has_escaping_regions() {
+            span_bug!(obligation.cause.span, "escaping regions in predicate {:?}",
+                      obligation);
+        }
         self.fulfillment_cx
             .borrow_mut()
             .register_predicate_obligation(self, obligation);
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 7f413a0dfc3..cf4dfd9e0ae 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -291,7 +291,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
                                         -> Ty<'tcx>
     {
         if let Some(trait_ref) = self.tcx().no_late_bound_regions(&poly_trait_ref) {
-            self.projected_ty(span, trait_ref, item_name)
+            self.tcx().mk_projection(trait_ref, item_name)
         } else {
             // no late-bound regions, we can just ignore the binder
             span_err!(self.tcx().sess, span, E0212,
@@ -301,13 +301,10 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
         }
     }
 
-    fn projected_ty(&self,
-                    _span: Span,
-                    trait_ref: ty::TraitRef<'tcx>,
-                    item_name: ast::Name)
-                    -> Ty<'tcx>
-    {
-        self.tcx().mk_projection(trait_ref, item_name)
+    fn normalize_ty(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        // types in item signatures are not normalized, to avoid undue
+        // dependencies.
+        ty
     }
 
     fn set_tainted_by_errors(&self) {
diff --git a/src/test/run-pass/issue-27901.rs b/src/test/run-pass/issue-27901.rs
new file mode 100644
index 00000000000..b7a9daaf8ab
--- /dev/null
+++ b/src/test/run-pass/issue-27901.rs
@@ -0,0 +1,20 @@
+// Copyright 2017 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 Stream { type Item; }
+impl<'a> Stream for &'a str { type Item = u8; }
+fn f<'s>(s: &'s str) -> (&'s str, <&'s str as Stream>::Item) {
+    (s, 42)
+}
+
+fn main() {
+    let fx = f as for<'t> fn(&'t str) -> (&'t str, <&'t str as Stream>::Item);
+    assert_eq!(fx("hi"), ("hi", 42));
+}
diff --git a/src/test/run-pass/issue-28828.rs b/src/test/run-pass/issue-28828.rs
new file mode 100644
index 00000000000..24e4b83e8a6
--- /dev/null
+++ b/src/test/run-pass/issue-28828.rs
@@ -0,0 +1,27 @@
+// Copyright 2017 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 Foo {
+    type Out;
+}
+
+impl Foo for () {
+    type Out = bool;
+}
+
+fn main() {
+    type Bool = <() as Foo>::Out;
+
+    let x: Bool = true;
+    assert!(x);
+
+    let y: Option<Bool> = None;
+    assert_eq!(y, None);
+}