diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 8125f432ff5a..36f6fa764390 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 4925c9d547e9..762aaf1ce1d1 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 b12c1220b2b4..7e349c6d0cb1 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 1032da7ef75b..a509587f80fd 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 011f7748f2c9..bf1d9886ae7f 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 f6cdd883850c..049178a2575f 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 = 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 d5f04542d025..6933f1582562 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 706f131ed627..cc9fd8f46f6f 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 d691fa6aadf2..d19f04b9554f 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 577fe31eab02..923ec05c22b7 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 0337727dcba9..c3271914768d 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 7f413a0dfc3a..cf4dfd9e0aeb 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 000000000000..b7a9daaf8abd --- /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 or the MIT license +// , 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 000000000000..24e4b83e8a67 --- /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 or the MIT license +// , 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 = None; + assert_eq!(y, None); +}