diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 10761a03bec0c..ed72fe1801663 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -816,12 +816,20 @@ pub enum Lvalue<'tcx> { Local(Local), /// static or static mut variable - Static(DefId), + Static(Box>), /// projection out of an lvalue (access a field, deref a pointer, etc) Projection(Box>), } +/// The def-id of a static, along with its normalized type (which is +/// stored to avoid requiring normalization when reading MIR). +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] +pub struct Static<'tcx> { + pub def_id: DefId, + pub ty: Ty<'tcx>, +} + /// The `Projection` data structure defines things of the form `B.x` /// or `*B` or `B[index]`. Note that it is parameterized because it is /// shared between `Constant` and `Lvalue`. See the aliases @@ -911,8 +919,8 @@ impl<'tcx> Debug for Lvalue<'tcx> { match *self { Local(id) => write!(fmt, "{:?}", id), - Static(def_id) => - write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))), + Static(box self::Static { def_id, ty }) => + write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.item_path_str(def_id)), ty), Projection(ref data) => match data.elem { ProjectionElem::Downcast(ref adt_def, index) => diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 14d3876a66e55..f40b9c6053753 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -125,8 +125,8 @@ impl<'tcx> Lvalue<'tcx> { match *self { Lvalue::Local(index) => LvalueTy::Ty { ty: mir.local_decls[index].ty }, - Lvalue::Static(def_id) => - LvalueTy::Ty { ty: tcx.item_type(def_id) }, + Lvalue::Static(ref data) => + LvalueTy::Ty { ty: data.ty }, Lvalue::Projection(ref proj) => proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem), } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 980d1806e78f8..733ad36de90e3 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -154,6 +154,13 @@ macro_rules! make_mir_visitor { self.super_lvalue(lvalue, context, location); } + fn visit_static(&mut self, + static_: & $($mutability)* Static<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { + self.super_static(static_, context, location); + } + fn visit_projection(&mut self, lvalue: & $($mutability)* LvalueProjection<'tcx>, context: LvalueContext<'tcx>, @@ -554,8 +561,8 @@ macro_rules! make_mir_visitor { match *lvalue { Lvalue::Local(_) => { } - Lvalue::Static(ref $($mutability)* def_id) => { - self.visit_def_id(def_id, location); + Lvalue::Static(ref $($mutability)* static_) => { + self.visit_static(static_, context, location); } Lvalue::Projection(ref $($mutability)* proj) => { self.visit_projection(proj, context, location); @@ -563,6 +570,18 @@ macro_rules! make_mir_visitor { } } + fn super_static(&mut self, + static_: & $($mutability)* Static<'tcx>, + _context: LvalueContext<'tcx>, + location: Location) { + let Static { + ref $($mutability)* def_id, + ref $($mutability)* ty, + } = *static_; + self.visit_def_id(def_id, location); + self.visit_ty(ty); + } + fn super_projection(&mut self, proj: & $($mutability)* LvalueProjection<'tcx>, context: LvalueContext<'tcx>, @@ -818,4 +837,3 @@ impl<'tcx> LvalueContext<'tcx> { self.is_mutating_use() || self.is_nonmutating_use() } } - diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 8886a310429ea..1cd9a1b25bade 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -86,7 +86,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.and(Lvalue::Local(index)) } ExprKind::StaticRef { id } => { - block.and(Lvalue::Static(id)) + block.and(Lvalue::Static(Box::new(Static { def_id: id, ty: expr.ty }))) } ExprKind::Array { .. } | diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index c99c4323bb8a1..f98bb73c504dc 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -25,22 +25,21 @@ use syntax_pos::{Span, DUMMY_SP}; use rustc_data_structures::indexed_vec::Idx; +fn mirbug(tcx: TyCtxt, span: Span, msg: &str) { + tcx.sess.diagnostic().span_bug(span, msg); +} + macro_rules! span_mirbug { ($context:expr, $elem:expr, $($message:tt)*) => ({ - $context.tcx().sess.span_warn( - $context.last_span, - &format!("broken MIR ({:?}): {}", $elem, format!($($message)*)) - ) + mirbug($context.tcx(), $context.last_span, + &format!("broken MIR ({:?}): {}", $elem, format!($($message)*))) }) } macro_rules! span_mirbug_and_err { ($context:expr, $elem:expr, $($message:tt)*) => ({ { - $context.tcx().sess.span_warn( - $context.last_span, - &format!("broken MIR ({:?}): {:?}", $elem, format!($($message)*)) - ); + span_mirbug!($context, $elem, $($message)*); $context.error() } }) @@ -125,8 +124,18 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { debug!("sanitize_lvalue: {:?}", lvalue); match *lvalue { Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty }, - Lvalue::Static(def_id) => - LvalueTy::Ty { ty: self.tcx().item_type(def_id) }, + Lvalue::Static(box Static { def_id, ty: sty }) => { + let sty = self.sanitize_type(lvalue, sty); + let ty = self.tcx().item_type(def_id); + let ty = self.cx.normalize(&ty); + if let Err(terr) = self.cx.eq_types(self.last_span, ty, sty) { + span_mirbug!( + self, lvalue, "bad static type ({:?}: {:?}): {:?}", + ty, sty, terr); + } + LvalueTy::Ty { ty: sty } + + }, Lvalue::Projection(ref proj) => { let base_ty = self.sanitize_lvalue(&proj.base, location); if let LvalueTy::Ty { ty } = base_ty { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 8125f432ff5ae..36f6fa7643909 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 4925c9d547e9d..762aaf1ce1d1b 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 632762857ef37..8d1db38999c6b 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 1032da7ef75bb..a509587f80fd0 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 011f7748f2c98..bf1d9886ae7f0 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 f6cdd883850cc..049178a2575f3 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 d5f04542d0255..6933f15825620 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/mir/constant.rs b/src/librustc_trans/mir/constant.rs index c524d8351e003..b6fcc990344ce 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -382,11 +382,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let lvalue = match *lvalue { mir::Lvalue::Local(_) => bug!(), // handled above - mir::Lvalue::Static(def_id) => { + mir::Lvalue::Static(box mir::Static { def_id, ty }) => { ConstLvalue { base: Base::Static(consts::get_static(self.ccx, def_id)), llextra: ptr::null_mut(), - ty: lvalue.ty(self.mir, tcx).to_ty(tcx) + ty: self.monomorphize(&ty), } } mir::Lvalue::Projection(ref projection) => { diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 2538f32031fdb..49e1e3855571b 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -304,10 +304,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let result = match *lvalue { mir::Lvalue::Local(_) => bug!(), // handled above - mir::Lvalue::Static(def_id) => { - let const_ty = self.monomorphized_lvalue_ty(lvalue); + mir::Lvalue::Static(box mir::Static { def_id, ty }) => { LvalueRef::new_sized(consts::get_static(ccx, def_id), - LvalueTy::from_ty(const_ty), + LvalueTy::from_ty(self.monomorphize(&ty)), Alignment::AbiAligned) }, mir::Lvalue::Projection(box mir::Projection { diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 706f131ed627f..cc9fd8f46f6f0 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 d691fa6aadf2e..d19f04b9554fb 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 577fe31eab02a..923ec05c22b77 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 126cd2302fb27..e8957bad0986c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -665,8 +665,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). @@ -1374,16 +1375,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) { @@ -1660,25 +1660,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()); } @@ -1709,9 +1690,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); @@ -1720,8 +1701,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); @@ -2040,10 +2024,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Neither => { if let Some(default) = default_map.get(ty) { let default = default.clone(); + let default_ty = self.normalize_associated_types_in( + default.origin_span, &default.ty); match self.eq_types(false, &self.misc(default.origin_span), ty, - default.ty) { + default_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => conflicts.push((*ty, default)), } @@ -4344,7 +4330,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else if !infer_types && def.has_default { // No type parameter provided, but a default exists. let default = self.tcx.item_type(def.def_id); - default.subst_spanned(self.tcx, substs, Some(span)) + self.normalize_ty( + span, + default.subst_spanned(self.tcx, substs, Some(span)) + ) } else { // No type parameters were provided, we can infer all. // This can also be reached in some error cases: diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1f622235af4b0..db7cf3c000ba4 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 0000000000000..b7a9daaf8abd4 --- /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 0000000000000..24e4b83e8a675 --- /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); +} diff --git a/src/test/run-pass/issue-39367.rs b/src/test/run-pass/issue-39367.rs new file mode 100644 index 0000000000000..3e72efada84e6 --- /dev/null +++ b/src/test/run-pass/issue-39367.rs @@ -0,0 +1,49 @@ +// 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. + +use std::ops::Deref; + +struct ArenaSet::Target>(U, &'static V) + where V: 'static + ?Sized; + +static Z: [u8; 4] = [1,2,3,4]; + +fn arena() -> &'static ArenaSet> { + fn __static_ref_initialize() -> ArenaSet> { + ArenaSet(vec![], &Z) + } + unsafe { + use std::sync::{Once, ONCE_INIT}; + fn require_sync(_: &T) { } + unsafe fn __stability() -> &'static ArenaSet> { + use std::mem::transmute; + use std::boxed::Box; + static mut DATA: *const ArenaSet> = 0 as *const ArenaSet>; + + static mut ONCE: Once = ONCE_INIT; + ONCE.call_once(|| { + DATA = transmute + ::>>, *const ArenaSet>> + (Box::new(__static_ref_initialize())); + }); + + &*DATA + } + let static_ref = __stability(); + require_sync(static_ref); + static_ref + } +} + +fn main() { + let &ArenaSet(ref u, v) = arena(); + assert!(u.is_empty()); + assert_eq!(v, Z); +}