From ca8708273b6d7ee506e7d03051778d520cfaa50f Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 1 Mar 2017 01:30:41 +0200 Subject: [PATCH 1/4] more through normalization in typeck & trans Fixes #27901. Fixes #28828. Fixes #38135. Fixes #39363. --- src/librustc_trans/base.rs | 9 +---- src/librustc_trans/callee.rs | 18 ++------- src/librustc_trans/collector.rs | 11 ++---- src/librustc_trans/common.rs | 12 +++++- src/librustc_trans/consts.rs | 9 +++-- src/librustc_trans/debuginfo/metadata.rs | 9 ++--- src/librustc_trans/debuginfo/mod.rs | 11 ++---- src/librustc_trans/partitioning.rs | 9 +---- src/librustc_trans/trans_item.rs | 9 ++--- src/librustc_typeck/astconv.rs | 24 ++++++------ src/librustc_typeck/check/mod.rs | 50 ++++++++---------------- src/librustc_typeck/collect.rs | 13 +++--- src/test/run-pass/issue-27901.rs | 20 ++++++++++ src/test/run-pass/issue-28828.rs | 27 +++++++++++++ 14 files changed, 121 insertions(+), 110 deletions(-) create mode 100644 src/test/run-pass/issue-27901.rs create mode 100644 src/test/run-pass/issue-28828.rs 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 b12c1220b2b4d..7e349c6d0cb1d 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/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 0337727dcba9a..c3271914768dd 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 7f413a0dfc3ab..cf4dfd9e0aeb1 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); +} From 34ff9aa83fa014f77ffe8fa5a12268a033c95694 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 1 Mar 2017 02:29:57 +0200 Subject: [PATCH 2/4] store the normalized types of statics in MIR Lvalues The types of statics, like all other items, are stored in the tcx unnormalized. This is necessarily so, because a) Item types other than statics have generics, which can't be normalized. b) Eager normalization causes undesirable on-demand dependencies. Keeping with the principle that MIR lvalues require no normalization in order to interpret, this patch stores the normalized type of the statics in the Lvalue and reads it to get the lvalue type. Fixes #39367. --- src/librustc/mir/mod.rs | 14 +++++-- src/librustc/mir/tcx.rs | 4 +- src/librustc/mir/visit.rs | 24 ++++++++++-- src/librustc_mir/build/expr/as_lvalue.rs | 2 +- src/librustc_mir/transform/type_check.rs | 14 ++++++- src/librustc_trans/mir/constant.rs | 4 +- src/librustc_trans/mir/lvalue.rs | 5 +-- src/test/run-pass/issue-39367.rs | 49 ++++++++++++++++++++++++ 8 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 src/test/run-pass/issue-39367.rs diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 40ebc97a78a6c..a7e89e77f3401 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 50a80305bee27..638655aee15aa 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 7cdbd5cae061f..1172172a845c2 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>, @@ -559,8 +566,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); @@ -568,6 +575,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>, @@ -837,4 +856,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 5abfe084f2258..ec412d4e9c62e 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -84,7 +84,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 af4a4a53905eb..c2faf27412c69 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -126,8 +126,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/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 771a5b7f366a1..fb2ef8f60c449 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/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); +} From 2ecbc22856f7ac6acf2de9af65af7bbc81b35250 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 1 Mar 2017 03:39:43 +0200 Subject: [PATCH 3/4] fix a few more typeck normalization cases I'll like @nikomatsakis or someone to look at the unsolved variable case. --- src/librustc_typeck/check/mod.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c3271914768dd..c42ef05bc5a77 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2092,10 +2092,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)), } @@ -4396,7 +4398,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: From 4aede759146260cddd194de71375d3f1b8183135 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 1 Mar 2017 02:44:01 +0200 Subject: [PATCH 4/4] transform broken MIR warnings to hard ICEs We ought to do that sometime, and this PR fixes all broken MIR errors I could find. --- src/librustc_mir/transform/type_check.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index c2faf27412c69..fb7d708778ef6 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() } })