| // Copyright 2012-2014 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. |
| |
| /* |
| |
| # Collect phase |
| |
| The collect phase of type check has the job of visiting all items, |
| determining their type, and writing that type into the `tcx.tcache` |
| table. Despite its name, this table does not really operate as a |
| *cache*, at least not for the types of items defined within the |
| current crate: we assume that after the collect phase, the types of |
| all local items will be present in the table. |
| |
| Unlike most of the types that are present in Rust, the types computed |
| for each item are in fact type schemes. This means that they are |
| generic types that may have type parameters. TypeSchemes are |
| represented by an instance of `ty::TypeScheme`. This combines the |
| core type along with a list of the bounds for each parameter. Type |
| parameters themselves are represented as `ty_param()` instances. |
| |
| The phasing of type conversion is somewhat complicated. There is no |
| clear set of phases we can enforce (e.g., converting traits first, |
| then types, or something like that) because the user can introduce |
| arbitrary interdependencies. So instead we generally convert things |
| lazilly and on demand, and include logic that checks for cycles. |
| Demand is driven by calls to `AstConv::get_item_type_scheme` or |
| `AstConv::lookup_trait_def`. |
| |
| Currently, we "convert" types and traits in two phases (note that |
| conversion only affects the types of items / enum variants / methods; |
| it does not e.g. compute the types of individual expressions): |
| |
| 0. Intrinsics |
| 1. Trait/Type definitions |
| |
| Conversion itself is done by simply walking each of the items in turn |
| and invoking an appropriate function (e.g., `trait_def_of_item` or |
| `convert_item`). However, it is possible that while converting an |
| item, we may need to compute the *type scheme* or *trait definition* |
| for other items. |
| |
| There are some shortcomings in this design: |
| |
| - Before walking the set of supertraits for a given trait, you must |
| call `ensure_super_predicates` on that trait def-id. Otherwise, |
| `lookup_super_predicates` will result in ICEs. |
| - Because the type scheme includes defaults, cycles through type |
| parameter defaults are illegal even if those defaults are never |
| employed. This is not necessarily a bug. |
| |
| */ |
| |
| use astconv::{AstConv, ast_region_to_region, Bounds, PartitionedBounds, partition_bounds}; |
| use lint; |
| use constrained_type_params as ctp; |
| use middle::lang_items::SizedTraitLangItem; |
| use middle::const_val::ConstVal; |
| use rustc_const_eval::EvalHint::UncheckedExprHint; |
| use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; |
| use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace}; |
| use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; |
| use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; |
| use rustc::ty::{VariantKind}; |
| use rustc::ty::util::IntTypeExt; |
| use rscope::*; |
| use rustc::dep_graph::DepNode; |
| use util::common::{ErrorReported, MemoizationMap}; |
| use util::nodemap::{NodeMap, FnvHashMap}; |
| use {CrateCtxt, write_ty_to_tcx}; |
| |
| use rustc_const_math::ConstInt; |
| |
| use std::cell::RefCell; |
| use std::collections::HashSet; |
| use std::collections::hash_map::Entry::{Occupied, Vacant}; |
| use std::rc::Rc; |
| |
| use syntax::{abi, ast, attr}; |
| use syntax::parse::token::keywords; |
| use syntax::ptr::P; |
| use syntax_pos::Span; |
| |
| use rustc::hir::{self, intravisit, map as hir_map, print as pprust}; |
| use rustc::hir::def::Def; |
| use rustc::hir::def_id::DefId; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // Main entry point |
| |
| pub fn collect_item_types(ccx: &CrateCtxt) { |
| let mut visitor = CollectItemTypesVisitor { ccx: ccx }; |
| ccx.tcx.visit_all_items_in_krate(DepNode::CollectItem, &mut visitor); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| |
| /// Context specific to some particular item. This is what implements |
| /// AstConv. It has information about the predicates that are defined |
| /// on the trait. Unfortunately, this predicate information is |
| /// available in various different forms at various points in the |
| /// process. So we can't just store a pointer to e.g. the AST or the |
| /// parsed ty form, we have to be more flexible. To this end, the |
| /// `ItemCtxt` is parameterized by a `GetTypeParameterBounds` object |
| /// that it uses to satisfy `get_type_parameter_bounds` requests. |
| /// This object might draw the information from the AST |
| /// (`hir::Generics`) or it might draw from a `ty::GenericPredicates` |
| /// or both (a tuple). |
| struct ItemCtxt<'a,'tcx:'a> { |
| ccx: &'a CrateCtxt<'a,'tcx>, |
| param_bounds: &'a (GetTypeParameterBounds<'tcx>+'a), |
| } |
| |
| #[derive(Copy, Clone, PartialEq, Eq)] |
| pub enum AstConvRequest { |
| GetItemTypeScheme(DefId), |
| GetTraitDef(DefId), |
| EnsureSuperPredicates(DefId), |
| GetTypeParameterBounds(ast::NodeId), |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| |
| struct CollectItemTypesVisitor<'a, 'tcx: 'a> { |
| ccx: &'a CrateCtxt<'a, 'tcx> |
| } |
| |
| impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> { |
| fn visit_item(&mut self, item: &hir::Item) { |
| convert_item(self.ccx, item); |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // Utility types and common code for the above passes. |
| |
| impl<'a,'tcx> CrateCtxt<'a,'tcx> { |
| fn icx(&'a self, param_bounds: &'a GetTypeParameterBounds<'tcx>) -> ItemCtxt<'a,'tcx> { |
| ItemCtxt { |
| ccx: self, |
| param_bounds: param_bounds, |
| } |
| } |
| |
| fn cycle_check<F,R>(&self, |
| span: Span, |
| request: AstConvRequest, |
| code: F) |
| -> Result<R,ErrorReported> |
| where F: FnOnce() -> Result<R,ErrorReported> |
| { |
| { |
| let mut stack = self.stack.borrow_mut(); |
| match stack.iter().enumerate().rev().find(|&(_, r)| *r == request) { |
| None => { } |
| Some((i, _)) => { |
| let cycle = &stack[i..]; |
| self.report_cycle(span, cycle); |
| return Err(ErrorReported); |
| } |
| } |
| stack.push(request); |
| } |
| |
| let result = code(); |
| |
| self.stack.borrow_mut().pop(); |
| result |
| } |
| |
| fn report_cycle(&self, |
| span: Span, |
| cycle: &[AstConvRequest]) |
| { |
| assert!(!cycle.is_empty()); |
| let tcx = self.tcx; |
| |
| let mut err = struct_span_err!(tcx.sess, span, E0391, |
| "unsupported cyclic reference between types/traits detected"); |
| |
| match cycle[0] { |
| AstConvRequest::GetItemTypeScheme(def_id) | |
| AstConvRequest::GetTraitDef(def_id) => { |
| err.note( |
| &format!("the cycle begins when processing `{}`...", |
| tcx.item_path_str(def_id))); |
| } |
| AstConvRequest::EnsureSuperPredicates(def_id) => { |
| err.note( |
| &format!("the cycle begins when computing the supertraits of `{}`...", |
| tcx.item_path_str(def_id))); |
| } |
| AstConvRequest::GetTypeParameterBounds(id) => { |
| let def = tcx.type_parameter_def(id); |
| err.note( |
| &format!("the cycle begins when computing the bounds \ |
| for type parameter `{}`...", |
| def.name)); |
| } |
| } |
| |
| for request in &cycle[1..] { |
| match *request { |
| AstConvRequest::GetItemTypeScheme(def_id) | |
| AstConvRequest::GetTraitDef(def_id) => { |
| err.note( |
| &format!("...which then requires processing `{}`...", |
| tcx.item_path_str(def_id))); |
| } |
| AstConvRequest::EnsureSuperPredicates(def_id) => { |
| err.note( |
| &format!("...which then requires computing the supertraits of `{}`...", |
| tcx.item_path_str(def_id))); |
| } |
| AstConvRequest::GetTypeParameterBounds(id) => { |
| let def = tcx.type_parameter_def(id); |
| err.note( |
| &format!("...which then requires computing the bounds \ |
| for type parameter `{}`...", |
| def.name)); |
| } |
| } |
| } |
| |
| match cycle[0] { |
| AstConvRequest::GetItemTypeScheme(def_id) | |
| AstConvRequest::GetTraitDef(def_id) => { |
| err.note( |
| &format!("...which then again requires processing `{}`, completing the cycle.", |
| tcx.item_path_str(def_id))); |
| } |
| AstConvRequest::EnsureSuperPredicates(def_id) => { |
| err.note( |
| &format!("...which then again requires computing the supertraits of `{}`, \ |
| completing the cycle.", |
| tcx.item_path_str(def_id))); |
| } |
| AstConvRequest::GetTypeParameterBounds(id) => { |
| let def = tcx.type_parameter_def(id); |
| err.note( |
| &format!("...which then again requires computing the bounds \ |
| for type parameter `{}`, completing the cycle.", |
| def.name)); |
| } |
| } |
| err.emit(); |
| } |
| |
| /// Loads the trait def for a given trait, returning ErrorReported if a cycle arises. |
| fn get_trait_def(&self, trait_id: DefId) |
| -> &'tcx ty::TraitDef<'tcx> |
| { |
| let tcx = self.tcx; |
| |
| if let Some(trait_id) = tcx.map.as_local_node_id(trait_id) { |
| let item = match tcx.map.get(trait_id) { |
| hir_map::NodeItem(item) => item, |
| _ => bug!("get_trait_def({:?}): not an item", trait_id) |
| }; |
| |
| trait_def_of_item(self, &item) |
| } else { |
| tcx.lookup_trait_def(trait_id) |
| } |
| } |
| |
| /// Ensure that the (transitive) super predicates for |
| /// `trait_def_id` are available. This will report a cycle error |
| /// if a trait `X` (transitively) extends itself in some form. |
| fn ensure_super_predicates(&self, span: Span, trait_def_id: DefId) |
| -> Result<(), ErrorReported> |
| { |
| self.cycle_check(span, AstConvRequest::EnsureSuperPredicates(trait_def_id), || { |
| let def_ids = ensure_super_predicates_step(self, trait_def_id); |
| |
| for def_id in def_ids { |
| self.ensure_super_predicates(span, def_id)?; |
| } |
| |
| Ok(()) |
| }) |
| } |
| } |
| |
| impl<'a,'tcx> ItemCtxt<'a,'tcx> { |
| fn to_ty<RS:RegionScope>(&self, rs: &RS, ast_ty: &hir::Ty) -> Ty<'tcx> { |
| AstConv::ast_ty_to_ty(self, rs, ast_ty) |
| } |
| } |
| |
| impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { |
| fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.ccx.tcx } |
| |
| fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>> { |
| &self.ccx.ast_ty_to_ty_cache |
| } |
| |
| fn get_item_type_scheme(&self, span: Span, id: DefId) |
| -> Result<ty::TypeScheme<'tcx>, ErrorReported> |
| { |
| self.ccx.cycle_check(span, AstConvRequest::GetItemTypeScheme(id), || { |
| Ok(type_scheme_of_def_id(self.ccx, id)) |
| }) |
| } |
| |
| fn get_trait_def(&self, span: Span, id: DefId) |
| -> Result<&'tcx ty::TraitDef<'tcx>, ErrorReported> |
| { |
| self.ccx.cycle_check(span, AstConvRequest::GetTraitDef(id), || { |
| Ok(self.ccx.get_trait_def(id)) |
| }) |
| } |
| |
| fn ensure_super_predicates(&self, |
| span: Span, |
| trait_def_id: DefId) |
| -> Result<(), ErrorReported> |
| { |
| debug!("ensure_super_predicates(trait_def_id={:?})", |
| trait_def_id); |
| |
| self.ccx.ensure_super_predicates(span, trait_def_id) |
| } |
| |
| |
| fn get_type_parameter_bounds(&self, |
| span: Span, |
| node_id: ast::NodeId) |
| -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported> |
| { |
| self.ccx.cycle_check(span, AstConvRequest::GetTypeParameterBounds(node_id), || { |
| let v = self.param_bounds.get_type_parameter_bounds(self, span, node_id) |
| .into_iter() |
| .filter_map(|p| p.to_opt_poly_trait_ref()) |
| .collect(); |
| Ok(v) |
| }) |
| } |
| |
| fn trait_defines_associated_type_named(&self, |
| trait_def_id: DefId, |
| assoc_name: ast::Name) |
| -> bool |
| { |
| if let Some(trait_id) = self.tcx().map.as_local_node_id(trait_def_id) { |
| trait_defines_associated_type_named(self.ccx, trait_id, assoc_name) |
| } else { |
| let trait_def = self.tcx().lookup_trait_def(trait_def_id); |
| trait_def.associated_type_names.contains(&assoc_name) |
| } |
| } |
| |
| fn get_free_substs(&self) -> Option<&Substs<'tcx>> { |
| None |
| } |
| |
| fn ty_infer(&self, |
| _ty_param_def: Option<ty::TypeParameterDef<'tcx>>, |
| _substs: Option<&mut Substs<'tcx>>, |
| _space: Option<ParamSpace>, |
| span: Span) -> Ty<'tcx> { |
| span_err!(self.tcx().sess, span, E0121, |
| "the type placeholder `_` is not allowed within types on item signatures"); |
| self.tcx().types.err |
| } |
| |
| fn projected_ty_from_poly_trait_ref(&self, |
| span: Span, |
| poly_trait_ref: ty::PolyTraitRef<'tcx>, |
| item_name: ast::Name) |
| -> Ty<'tcx> |
| { |
| if let Some(trait_ref) = self.tcx().no_late_bound_regions(&poly_trait_ref) { |
| self.projected_ty(span, trait_ref, item_name) |
| } else { |
| // no late-bound regions, we can just ignore the binder |
| span_err!(self.tcx().sess, span, E0212, |
| "cannot extract an associated type from a higher-ranked trait bound \ |
| in this context"); |
| self.tcx().types.err |
| } |
| } |
| |
| 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 set_tainted_by_errors(&self) { |
| // no obvious place to track this, just let it go |
| } |
| } |
| |
| /// Interface used to find the bounds on a type parameter from within |
| /// an `ItemCtxt`. This allows us to use multiple kinds of sources. |
| trait GetTypeParameterBounds<'tcx> { |
| fn get_type_parameter_bounds(&self, |
| astconv: &AstConv<'tcx, 'tcx>, |
| span: Span, |
| node_id: ast::NodeId) |
| -> Vec<ty::Predicate<'tcx>>; |
| } |
| |
| /// Find bounds from both elements of the tuple. |
| impl<'a,'b,'tcx,A,B> GetTypeParameterBounds<'tcx> for (&'a A,&'b B) |
| where A : GetTypeParameterBounds<'tcx>, B : GetTypeParameterBounds<'tcx> |
| { |
| fn get_type_parameter_bounds(&self, |
| astconv: &AstConv<'tcx, 'tcx>, |
| span: Span, |
| node_id: ast::NodeId) |
| -> Vec<ty::Predicate<'tcx>> |
| { |
| let mut v = self.0.get_type_parameter_bounds(astconv, span, node_id); |
| v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id)); |
| v |
| } |
| } |
| |
| /// Empty set of bounds. |
| impl<'tcx> GetTypeParameterBounds<'tcx> for () { |
| fn get_type_parameter_bounds(&self, |
| _astconv: &AstConv<'tcx, 'tcx>, |
| _span: Span, |
| _node_id: ast::NodeId) |
| -> Vec<ty::Predicate<'tcx>> |
| { |
| Vec::new() |
| } |
| } |
| |
| /// Find bounds from the parsed and converted predicates. This is |
| /// used when converting methods, because by that time the predicates |
| /// from the trait/impl have been fully converted. |
| impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { |
| fn get_type_parameter_bounds(&self, |
| astconv: &AstConv<'tcx, 'tcx>, |
| _span: Span, |
| node_id: ast::NodeId) |
| -> Vec<ty::Predicate<'tcx>> |
| { |
| let def = astconv.tcx().type_parameter_def(node_id); |
| |
| self.predicates |
| .iter() |
| .filter(|predicate| { |
| match **predicate { |
| ty::Predicate::Trait(ref data) => { |
| data.skip_binder().self_ty().is_param(def.space, def.index) |
| } |
| ty::Predicate::TypeOutlives(ref data) => { |
| data.skip_binder().0.is_param(def.space, def.index) |
| } |
| ty::Predicate::Rfc1592(..) | |
| ty::Predicate::Equate(..) | |
| ty::Predicate::RegionOutlives(..) | |
| ty::Predicate::WellFormed(..) | |
| ty::Predicate::ObjectSafe(..) | |
| ty::Predicate::ClosureKind(..) | |
| ty::Predicate::Projection(..) => { |
| false |
| } |
| } |
| }) |
| .cloned() |
| .collect() |
| } |
| } |
| |
| /// Find bounds from hir::Generics. This requires scanning through the |
| /// AST. We do this to avoid having to convert *all* the bounds, which |
| /// would create artificial cycles. Instead we can only convert the |
| /// bounds for a type parameter `X` if `X::Foo` is used. |
| impl<'tcx> GetTypeParameterBounds<'tcx> for hir::Generics { |
| fn get_type_parameter_bounds(&self, |
| astconv: &AstConv<'tcx, 'tcx>, |
| _: Span, |
| node_id: ast::NodeId) |
| -> Vec<ty::Predicate<'tcx>> |
| { |
| // In the AST, bounds can derive from two places. Either |
| // written inline like `<T:Foo>` or in a where clause like |
| // `where T:Foo`. |
| |
| let def = astconv.tcx().type_parameter_def(node_id); |
| let ty = astconv.tcx().mk_param_from_def(&def); |
| |
| let from_ty_params = |
| self.ty_params |
| .iter() |
| .filter(|p| p.id == node_id) |
| .flat_map(|p| p.bounds.iter()) |
| .flat_map(|b| predicates_from_bound(astconv, ty, b)); |
| |
| let from_where_clauses = |
| self.where_clause |
| .predicates |
| .iter() |
| .filter_map(|wp| match *wp { |
| hir::WherePredicate::BoundPredicate(ref bp) => Some(bp), |
| _ => None |
| }) |
| .filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id)) |
| .flat_map(|bp| bp.bounds.iter()) |
| .flat_map(|b| predicates_from_bound(astconv, ty, b)); |
| |
| from_ty_params.chain(from_where_clauses).collect() |
| } |
| } |
| |
| /// Tests whether this is the AST for a reference to the type |
| /// parameter with id `param_id`. We use this so as to avoid running |
| /// `ast_ty_to_ty`, because we want to avoid triggering an all-out |
| /// conversion of the type to avoid inducing unnecessary cycles. |
| fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
| ast_ty: &hir::Ty, |
| param_id: ast::NodeId) |
| -> bool |
| { |
| if let hir::TyPath(None, _) = ast_ty.node { |
| let path_res = tcx.expect_resolution(ast_ty.id); |
| match path_res.base_def { |
| Def::SelfTy(Some(def_id), None) | |
| Def::TyParam(_, _, def_id, _) if path_res.depth == 0 => { |
| def_id == tcx.map.local_def_id(param_id) |
| } |
| _ => false |
| } |
| } else { |
| false |
| } |
| } |
| |
| |
| fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| container: ImplOrTraitItemContainer, |
| name: ast::Name, |
| id: ast::NodeId, |
| vis: &hir::Visibility, |
| sig: &hir::MethodSig, |
| defaultness: hir::Defaultness, |
| untransformed_rcvr_ty: Ty<'tcx>, |
| rcvr_ty_generics: &ty::Generics<'tcx>, |
| rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) { |
| let ty_generics = ty_generics_for_fn(ccx, &sig.generics, rcvr_ty_generics); |
| |
| let ty_generic_predicates = |
| ty_generic_predicates_for_fn(ccx, &sig.generics, rcvr_ty_predicates); |
| |
| let (fty, explicit_self_category) = |
| AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), |
| sig, |
| untransformed_rcvr_ty); |
| |
| let def_id = ccx.tcx.map.local_def_id(id); |
| let substs = mk_item_substs(ccx, &ty_generics); |
| |
| let ty_method = ty::Method::new(name, |
| ty_generics, |
| ty_generic_predicates, |
| fty, |
| explicit_self_category, |
| ty::Visibility::from_hir(vis, id, ccx.tcx), |
| defaultness, |
| def_id, |
| container); |
| |
| let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty); |
| debug!("method {} (id {}) has type {:?}", |
| name, id, fty); |
| ccx.tcx.register_item_type(def_id, TypeScheme { |
| generics: ty_method.generics.clone(), |
| ty: fty |
| }); |
| ccx.tcx.predicates.borrow_mut().insert(def_id, ty_method.predicates.clone()); |
| |
| write_ty_to_tcx(ccx, id, fty); |
| |
| debug!("writing method type: def_id={:?} mty={:?}", |
| def_id, ty_method); |
| |
| ccx.tcx.impl_or_trait_items.borrow_mut().insert(def_id, |
| ty::MethodTraitItem(Rc::new(ty_method))); |
| } |
| |
| fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| struct_generics: &ty::Generics<'tcx>, |
| struct_predicates: &ty::GenericPredicates<'tcx>, |
| field: &hir::StructField, |
| ty_f: ty::FieldDefMaster<'tcx>) |
| { |
| let tt = ccx.icx(struct_predicates).to_ty(&ExplicitRscope, &field.ty); |
| ty_f.fulfill_ty(tt); |
| write_ty_to_tcx(ccx, field.id, tt); |
| |
| /* add the field to the tcache */ |
| ccx.tcx.register_item_type(ccx.tcx.map.local_def_id(field.id), |
| ty::TypeScheme { |
| generics: struct_generics.clone(), |
| ty: tt |
| }); |
| ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(field.id), |
| struct_predicates.clone()); |
| } |
| |
| fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| container: ImplOrTraitItemContainer, |
| name: ast::Name, |
| id: ast::NodeId, |
| vis: &hir::Visibility, |
| defaultness: hir::Defaultness, |
| ty: ty::Ty<'tcx>, |
| has_value: bool) |
| { |
| ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id), |
| ty::GenericPredicates::empty()); |
| |
| write_ty_to_tcx(ccx, id, ty); |
| |
| let associated_const = Rc::new(ty::AssociatedConst { |
| name: name, |
| vis: ty::Visibility::from_hir(vis, id, ccx.tcx), |
| defaultness: defaultness, |
| def_id: ccx.tcx.map.local_def_id(id), |
| container: container, |
| ty: ty, |
| has_value: has_value |
| }); |
| ccx.tcx.impl_or_trait_items.borrow_mut() |
| .insert(ccx.tcx.map.local_def_id(id), ty::ConstTraitItem(associated_const)); |
| } |
| |
| fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| container: ImplOrTraitItemContainer, |
| name: ast::Name, |
| id: ast::NodeId, |
| vis: &hir::Visibility, |
| defaultness: hir::Defaultness, |
| ty: Option<Ty<'tcx>>) |
| { |
| let associated_type = Rc::new(ty::AssociatedType { |
| name: name, |
| vis: ty::Visibility::from_hir(vis, id, ccx.tcx), |
| defaultness: defaultness, |
| ty: ty, |
| def_id: ccx.tcx.map.local_def_id(id), |
| container: container |
| }); |
| ccx.tcx.impl_or_trait_items.borrow_mut() |
| .insert(ccx.tcx.map.local_def_id(id), ty::TypeTraitItem(associated_type)); |
| } |
| |
| fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, |
| span: Span, |
| generics: &hir::Generics, |
| thing: &'static str) { |
| let mut warn = false; |
| |
| for ty_param in generics.ty_params.iter() { |
| for bound in ty_param.bounds.iter() { |
| match *bound { |
| hir::TraitTyParamBound(..) => { |
| warn = true; |
| } |
| hir::RegionTyParamBound(..) => { } |
| } |
| } |
| } |
| |
| if warn { |
| // According to accepted RFC #XXX, we should |
| // eventually accept these, but it will not be |
| // part of this PR. Still, convert to warning to |
| // make bootstrapping easier. |
| span_warn!(ccx.tcx.sess, span, E0122, |
| "trait bounds are not (yet) enforced \ |
| in {} definitions", |
| thing); |
| } |
| } |
| |
| fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { |
| let tcx = ccx.tcx; |
| debug!("convert: item {} with id {}", it.name, it.id); |
| match it.node { |
| // These don't define types. |
| hir::ItemExternCrate(_) | hir::ItemUse(_) | hir::ItemMod(_) => { |
| } |
| hir::ItemForeignMod(ref foreign_mod) => { |
| for item in &foreign_mod.items { |
| convert_foreign_item(ccx, item); |
| } |
| } |
| hir::ItemEnum(ref enum_definition, _) => { |
| let (scheme, predicates) = convert_typed_item(ccx, it); |
| write_ty_to_tcx(ccx, it.id, scheme.ty); |
| convert_enum_variant_types(ccx, |
| tcx.lookup_adt_def_master(ccx.tcx.map.local_def_id(it.id)), |
| scheme, |
| predicates, |
| &enum_definition.variants); |
| }, |
| hir::ItemDefaultImpl(_, ref ast_trait_ref) => { |
| let trait_ref = |
| AstConv::instantiate_mono_trait_ref(&ccx.icx(&()), |
| &ExplicitRscope, |
| ast_trait_ref, |
| None); |
| |
| tcx.record_trait_has_default_impl(trait_ref.def_id); |
| |
| tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), |
| Some(trait_ref)); |
| } |
| hir::ItemImpl(_, _, |
| ref generics, |
| ref opt_trait_ref, |
| ref selfty, |
| ref impl_items) => { |
| // Create generics from the generics specified in the impl head. |
| debug!("convert: ast_generics={:?}", generics); |
| let def_id = ccx.tcx.map.local_def_id(it.id); |
| let ty_generics = ty_generics_for_impl(ccx, generics); |
| let mut ty_predicates = ty_generic_predicates_for_type_or_impl(ccx, generics); |
| |
| debug!("convert: impl_bounds={:?}", ty_predicates); |
| |
| let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &selfty); |
| write_ty_to_tcx(ccx, it.id, selfty); |
| |
| tcx.register_item_type(def_id, |
| TypeScheme { generics: ty_generics.clone(), |
| ty: selfty }); |
| let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| { |
| AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), |
| &ExplicitRscope, |
| ast_trait_ref, |
| Some(selfty)) |
| }); |
| tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref); |
| |
| enforce_impl_params_are_constrained(ccx, generics, &mut ty_predicates, def_id); |
| tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone()); |
| |
| |
| // Convert all the associated consts. |
| // Also, check if there are any duplicate associated items |
| let mut seen_type_items = FnvHashMap(); |
| let mut seen_value_items = FnvHashMap(); |
| |
| for impl_item in impl_items { |
| let seen_items = match impl_item.node { |
| hir::ImplItemKind::Type(_) => &mut seen_type_items, |
| _ => &mut seen_value_items, |
| }; |
| match seen_items.entry(impl_item.name) { |
| Occupied(entry) => { |
| let mut err = struct_span_err!(tcx.sess, impl_item.span, E0201, |
| "duplicate definitions with name `{}`:", |
| impl_item.name); |
| span_note!(&mut err, *entry.get(), |
| "previous definition of `{}` here", |
| impl_item.name); |
| err.emit(); |
| } |
| Vacant(entry) => { |
| entry.insert(impl_item.span); |
| } |
| } |
| |
| if let hir::ImplItemKind::Const(ref ty, _) = impl_item.node { |
| let ty = ccx.icx(&ty_predicates) |
| .to_ty(&ExplicitRscope, &ty); |
| tcx.register_item_type(ccx.tcx.map.local_def_id(impl_item.id), |
| TypeScheme { |
| generics: ty_generics.clone(), |
| ty: ty, |
| }); |
| // Trait-associated constants are always public. |
| let public = &hir::Public; |
| let visibility = if opt_trait_ref.is_some() { public } else { &impl_item.vis }; |
| convert_associated_const(ccx, ImplContainer(def_id), |
| impl_item.name, impl_item.id, |
| visibility, |
| impl_item.defaultness, |
| ty, true /* has_value */); |
| } |
| } |
| |
| // Convert all the associated types. |
| for impl_item in impl_items { |
| if let hir::ImplItemKind::Type(ref ty) = impl_item.node { |
| if opt_trait_ref.is_none() { |
| span_err!(tcx.sess, impl_item.span, E0202, |
| "associated types are not allowed in inherent impls"); |
| } |
| |
| let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); |
| |
| convert_associated_type(ccx, ImplContainer(def_id), |
| impl_item.name, impl_item.id, &impl_item.vis, |
| impl_item.defaultness, Some(typ)); |
| } |
| } |
| |
| for impl_item in impl_items { |
| if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { |
| // Trait methods are always public. |
| let public = &hir::Public; |
| let method_vis = if opt_trait_ref.is_some() { public } else { &impl_item.vis }; |
| |
| convert_method(ccx, ImplContainer(def_id), |
| impl_item.name, impl_item.id, method_vis, |
| sig, impl_item.defaultness, selfty, &ty_generics, |
| &ty_predicates); |
| } |
| } |
| |
| enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_items); |
| }, |
| hir::ItemTrait(_, _, _, ref trait_items) => { |
| let trait_def = trait_def_of_item(ccx, it); |
| let def_id = trait_def.trait_ref.def_id; |
| let _: Result<(), ErrorReported> = // any error is already reported, can ignore |
| ccx.ensure_super_predicates(it.span, def_id); |
| convert_trait_predicates(ccx, it); |
| let trait_predicates = tcx.lookup_predicates(def_id); |
| |
| debug!("convert: trait_bounds={:?}", trait_predicates); |
| |
| // FIXME: is the ordering here important? I think it is. |
| let container = TraitContainer(def_id); |
| |
| // Convert all the associated constants. |
| for trait_item in trait_items { |
| if let hir::ConstTraitItem(ref ty, ref default) = trait_item.node { |
| let ty = ccx.icx(&trait_predicates) |
| .to_ty(&ExplicitRscope, ty); |
| tcx.register_item_type(ccx.tcx.map.local_def_id(trait_item.id), |
| TypeScheme { |
| generics: trait_def.generics.clone(), |
| ty: ty, |
| }); |
| convert_associated_const(ccx, |
| container, |
| trait_item.name, |
| trait_item.id, |
| &hir::Public, |
| hir::Defaultness::Default, |
| ty, |
| default.is_some()) |
| } |
| } |
| |
| // Convert all the associated types. |
| for trait_item in trait_items { |
| if let hir::TypeTraitItem(_, ref opt_ty) = trait_item.node { |
| let typ = opt_ty.as_ref().map({ |
| |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty) |
| }); |
| |
| convert_associated_type(ccx, |
| container, |
| trait_item.name, |
| trait_item.id, |
| &hir::Public, |
| hir::Defaultness::Default, |
| typ); |
| } |
| } |
| |
| // Convert all the methods |
| for trait_item in trait_items { |
| if let hir::MethodTraitItem(ref sig, _) = trait_item.node { |
| convert_method(ccx, |
| container, |
| trait_item.name, |
| trait_item.id, |
| &hir::Inherited, |
| sig, |
| hir::Defaultness::Default, |
| tcx.mk_self_type(), |
| &trait_def.generics, |
| &trait_predicates); |
| |
| } |
| } |
| |
| // Add an entry mapping |
| let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| { |
| let def_id = ccx.tcx.map.local_def_id(trait_item.id); |
| match trait_item.node { |
| hir::ConstTraitItem(..) => ty::ConstTraitItemId(def_id), |
| hir::MethodTraitItem(..) => ty::MethodTraitItemId(def_id), |
| hir::TypeTraitItem(..) => ty::TypeTraitItemId(def_id) |
| } |
| }).collect()); |
| tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), |
| trait_item_def_ids); |
| }, |
| hir::ItemStruct(ref struct_def, _) => { |
| let (scheme, predicates) = convert_typed_item(ccx, it); |
| write_ty_to_tcx(ccx, it.id, scheme.ty); |
| |
| let it_def_id = ccx.tcx.map.local_def_id(it.id); |
| let variant = tcx.lookup_adt_def_master(it_def_id).struct_variant(); |
| |
| for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) { |
| convert_field(ccx, &scheme.generics, &predicates, f, ty_f) |
| } |
| |
| if !struct_def.is_struct() { |
| convert_variant_ctor(ccx, struct_def.id(), variant, scheme, predicates); |
| } |
| }, |
| hir::ItemTy(_, ref generics) => { |
| ensure_no_ty_param_bounds(ccx, it.span, generics, "type"); |
| let (scheme, _) = convert_typed_item(ccx, it); |
| write_ty_to_tcx(ccx, it.id, scheme.ty); |
| }, |
| _ => { |
| // This call populates the type cache with the converted type |
| // of the item in passing. All we have to do here is to write |
| // it into the node type table. |
| let (scheme, _) = convert_typed_item(ccx, it); |
| write_ty_to_tcx(ccx, it.id, scheme.ty); |
| }, |
| } |
| } |
| |
| fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| ctor_id: ast::NodeId, |
| variant: ty::VariantDef<'tcx>, |
| scheme: ty::TypeScheme<'tcx>, |
| predicates: ty::GenericPredicates<'tcx>) { |
| let tcx = ccx.tcx; |
| let ctor_ty = match variant.kind { |
| VariantKind::Unit | VariantKind::Struct => scheme.ty, |
| VariantKind::Tuple => { |
| let inputs: Vec<_> = |
| variant.fields |
| .iter() |
| .map(|field| field.unsubst_ty()) |
| .collect(); |
| let def_id = tcx.map.local_def_id(ctor_id); |
| let substs = mk_item_substs(ccx, &scheme.generics); |
| tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { |
| unsafety: hir::Unsafety::Normal, |
| abi: abi::Abi::Rust, |
| sig: ty::Binder(ty::FnSig { |
| inputs: inputs, |
| output: ty::FnConverging(scheme.ty), |
| variadic: false |
| }) |
| })) |
| } |
| }; |
| write_ty_to_tcx(ccx, ctor_id, ctor_ty); |
| tcx.predicates.borrow_mut().insert(tcx.map.local_def_id(ctor_id), predicates); |
| tcx.register_item_type(tcx.map.local_def_id(ctor_id), |
| TypeScheme { |
| generics: scheme.generics, |
| ty: ctor_ty |
| }); |
| } |
| |
| fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| def: ty::AdtDefMaster<'tcx>, |
| scheme: ty::TypeScheme<'tcx>, |
| predicates: ty::GenericPredicates<'tcx>, |
| variants: &[hir::Variant]) { |
| // fill the field types |
| for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) { |
| for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) { |
| convert_field(ccx, &scheme.generics, &predicates, f, ty_f) |
| } |
| |
| // Convert the ctor, if any. This also registers the variant as |
| // an item. |
| convert_variant_ctor( |
| ccx, |
| variant.node.data.id(), |
| ty_variant, |
| scheme.clone(), |
| predicates.clone() |
| ); |
| } |
| } |
| |
| fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| did: DefId, |
| name: ast::Name, |
| disr_val: ty::Disr, |
| def: &hir::VariantData) |
| -> ty::VariantDefData<'tcx, 'tcx> { |
| let mut seen_fields: FnvHashMap<ast::Name, Span> = FnvHashMap(); |
| let node_id = ccx.tcx.map.as_local_node_id(did).unwrap(); |
| let fields = def.fields().iter().map(|f| { |
| let fid = ccx.tcx.map.local_def_id(f.id); |
| let dup_span = seen_fields.get(&f.name).cloned(); |
| if let Some(prev_span) = dup_span { |
| let mut err = struct_span_err!(ccx.tcx.sess, f.span, E0124, |
| "field `{}` is already declared", |
| f.name); |
| span_note!(&mut err, prev_span, "previously declared here"); |
| err.emit(); |
| } else { |
| seen_fields.insert(f.name, f.span); |
| } |
| |
| ty::FieldDefData::new(fid, f.name, |
| ty::Visibility::from_hir(&f.vis, node_id, ccx.tcx)) |
| }).collect(); |
| ty::VariantDefData { |
| did: did, |
| name: name, |
| disr_val: disr_val, |
| fields: fields, |
| kind: VariantKind::from_variant_data(def), |
| } |
| } |
| |
| fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| it: &hir::Item, |
| def: &hir::VariantData) |
| -> ty::AdtDefMaster<'tcx> |
| { |
| let did = ccx.tcx.map.local_def_id(it.id); |
| // Use separate constructor id for unit/tuple structs and reuse did for braced structs. |
| let ctor_id = if !def.is_struct() { Some(ccx.tcx.map.local_def_id(def.id())) } else { None }; |
| let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, |
| ConstInt::Infer(0), def)]; |
| let adt = ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct, variants); |
| if let Some(ctor_id) = ctor_id { |
| // Make adt definition available through constructor id as well. |
| ccx.tcx.insert_adt_def(ctor_id, adt); |
| } |
| adt |
| } |
| |
| fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr) |
| -> Option<ty::Disr> { |
| debug!("disr expr, checking {}", pprust::expr_to_string(e)); |
| |
| let ty_hint = repr_ty.to_ty(ccx.tcx); |
| let print_err = |cv: ConstVal| { |
| struct_span_err!(ccx.tcx.sess, e.span, E0079, "mismatched types") |
| .note_expected_found(&"type", &ty_hint, &format!("{}", cv.description())) |
| .emit(); |
| }; |
| |
| let hint = UncheckedExprHint(ty_hint); |
| match eval_const_expr_partial(ccx.tcx, e, hint, None) { |
| Ok(ConstVal::Integral(i)) => { |
| // FIXME: eval_const_expr_partial should return an error if the hint is wrong |
| match (repr_ty, i) { |
| (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) | |
| (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) | |
| (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) | |
| (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) | |
| (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) | |
| (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) | |
| (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) | |
| (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) | |
| (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) | |
| (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Some(i), |
| (_, i) => { |
| print_err(ConstVal::Integral(i)); |
| None |
| }, |
| } |
| }, |
| Ok(cv) => { |
| print_err(cv); |
| None |
| }, |
| // enum variant evaluation happens before the global constant check |
| // so we need to report the real error |
| Err(err) => { |
| let mut diag = report_const_eval_err( |
| ccx.tcx, &err, e.span, "enum discriminant"); |
| diag.emit(); |
| None |
| } |
| } |
| } |
| |
| fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| it: &hir::Item, |
| def: &hir::EnumDef) |
| -> ty::AdtDefMaster<'tcx> |
| { |
| let tcx = ccx.tcx; |
| let did = tcx.map.local_def_id(it.id); |
| let repr_hints = tcx.lookup_repr_hints(did); |
| let repr_type = tcx.enum_repr_type(repr_hints.get(0)); |
| let initial = repr_type.initial_discriminant(tcx); |
| let mut prev_disr = None::<ty::Disr>; |
| let variants = def.variants.iter().map(|v| { |
| let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr()); |
| let disr = if let Some(ref e) = v.node.disr_expr { |
| evaluate_disr_expr(ccx, repr_type, e) |
| } else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) { |
| Some(disr) |
| } else { |
| span_err!(tcx.sess, v.span, E0370, |
| "enum discriminant overflowed on value after {}; \ |
| set explicitly via {} = {} if that is desired outcome", |
| prev_disr.unwrap(), v.node.name, wrapped_disr); |
| None |
| }.unwrap_or(wrapped_disr); |
| prev_disr = Some(disr); |
| |
| let did = tcx.map.local_def_id(v.node.data.id()); |
| convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data) |
| }).collect(); |
| tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants) |
| } |
| |
| /// Ensures that the super-predicates of the trait with def-id |
| /// trait_def_id are converted and stored. This does NOT ensure that |
| /// the transitive super-predicates are converted; that is the job of |
| /// the `ensure_super_predicates()` method in the `AstConv` impl |
| /// above. Returns a list of trait def-ids that must be ensured as |
| /// well to guarantee that the transitive superpredicates are |
| /// converted. |
| fn ensure_super_predicates_step(ccx: &CrateCtxt, |
| trait_def_id: DefId) |
| -> Vec<DefId> |
| { |
| let tcx = ccx.tcx; |
| |
| debug!("ensure_super_predicates_step(trait_def_id={:?})", trait_def_id); |
| |
| let trait_node_id = if let Some(n) = tcx.map.as_local_node_id(trait_def_id) { |
| n |
| } else { |
| // If this trait comes from an external crate, then all of the |
| // supertraits it may depend on also must come from external |
| // crates, and hence all of them already have their |
| // super-predicates "converted" (and available from crate |
| // meta-data), so there is no need to transitively test them. |
| return Vec::new(); |
| }; |
| |
| let superpredicates = tcx.super_predicates.borrow().get(&trait_def_id).cloned(); |
| let superpredicates = superpredicates.unwrap_or_else(|| { |
| let item = match ccx.tcx.map.get(trait_node_id) { |
| hir_map::NodeItem(item) => item, |
| _ => bug!("trait_node_id {} is not an item", trait_node_id) |
| }; |
| |
| let (generics, bounds) = match item.node { |
| hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits), |
| _ => span_bug!(item.span, |
| "ensure_super_predicates_step invoked on non-trait"), |
| }; |
| |
| // In-scope when converting the superbounds for `Trait` are |
| // that `Self:Trait` as well as any bounds that appear on the |
| // generic types: |
| let trait_def = trait_def_of_item(ccx, item); |
| let self_predicate = ty::GenericPredicates { |
| predicates: VecPerParamSpace::new(vec![], |
| vec![trait_def.trait_ref.to_predicate()], |
| vec![]) |
| }; |
| let scope = &(generics, &self_predicate); |
| |
| // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`. |
| let self_param_ty = tcx.mk_self_type(); |
| let superbounds1 = compute_bounds(&ccx.icx(scope), |
| self_param_ty, |
| bounds, |
| SizedByDefault::No, |
| item.span); |
| |
| let superbounds1 = superbounds1.predicates(tcx, self_param_ty); |
| |
| // Convert any explicit superbounds in the where clause, |
| // e.g. `trait Foo where Self : Bar`: |
| let superbounds2 = generics.get_type_parameter_bounds(&ccx.icx(scope), item.span, item.id); |
| |
| // Combine the two lists to form the complete set of superbounds: |
| let superbounds = superbounds1.into_iter().chain(superbounds2).collect(); |
| let superpredicates = ty::GenericPredicates { |
| predicates: VecPerParamSpace::new(superbounds, vec![], vec![]) |
| }; |
| debug!("superpredicates for trait {:?} = {:?}", |
| tcx.map.local_def_id(item.id), |
| superpredicates); |
| |
| tcx.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone()); |
| |
| superpredicates |
| }); |
| |
| let def_ids: Vec<_> = superpredicates.predicates |
| .iter() |
| .filter_map(|p| p.to_opt_poly_trait_ref()) |
| .map(|tr| tr.def_id()) |
| .collect(); |
| |
| debug!("ensure_super_predicates_step: def_ids={:?}", def_ids); |
| |
| def_ids |
| } |
| |
| fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| it: &hir::Item) |
| -> &'tcx ty::TraitDef<'tcx> |
| { |
| let def_id = ccx.tcx.map.local_def_id(it.id); |
| let tcx = ccx.tcx; |
| |
| if let Some(def) = tcx.trait_defs.borrow().get(&def_id) { |
| return def.clone(); |
| } |
| |
| let (unsafety, generics, items) = match it.node { |
| hir::ItemTrait(unsafety, ref generics, _, ref items) => (unsafety, generics, items), |
| _ => span_bug!(it.span, "trait_def_of_item invoked on non-trait"), |
| }; |
| |
| let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar"); |
| if paren_sugar && !ccx.tcx.sess.features.borrow().unboxed_closures { |
| let mut err = ccx.tcx.sess.struct_span_err( |
| it.span, |
| "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \ |
| which traits can use parenthetical notation"); |
| help!(&mut err, |
| "add `#![feature(unboxed_closures)]` to \ |
| the crate attributes to use it"); |
| err.emit(); |
| } |
| |
| let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, generics)); |
| |
| let ty_generics = ty_generics_for_trait(ccx, it.id, substs, generics); |
| |
| let associated_type_names: Vec<_> = items.iter().filter_map(|trait_item| { |
| match trait_item.node { |
| hir::TypeTraitItem(..) => Some(trait_item.name), |
| _ => None, |
| } |
| }).collect(); |
| |
| let trait_ref = ty::TraitRef { |
| def_id: def_id, |
| substs: substs, |
| }; |
| |
| let trait_def = ty::TraitDef::new(unsafety, |
| paren_sugar, |
| ty_generics, |
| trait_ref, |
| associated_type_names); |
| |
| return tcx.intern_trait_def(trait_def); |
| |
| fn mk_trait_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| generics: &hir::Generics) |
| -> Substs<'tcx> |
| { |
| let tcx = ccx.tcx; |
| |
| // Creates a no-op substitution for the trait's type parameters. |
| let regions = |
| generics.lifetimes |
| .iter() |
| .enumerate() |
| .map(|(i, def)| ty::ReEarlyBound(ty::EarlyBoundRegion { |
| space: TypeSpace, |
| index: i as u32, |
| name: def.lifetime.name |
| })) |
| .collect(); |
| |
| // Start with the generics in the type parameters... |
| let types: Vec<_> = |
| generics.ty_params |
| .iter() |
| .enumerate() |
| .map(|(i, def)| tcx.mk_param(TypeSpace, |
| i as u32, def.name)) |
| .collect(); |
| |
| // ...and also create the `Self` parameter. |
| let self_ty = tcx.mk_self_type(); |
| |
| Substs::new_trait(types, regions, self_ty) |
| } |
| } |
| |
| fn trait_defines_associated_type_named(ccx: &CrateCtxt, |
| trait_node_id: ast::NodeId, |
| assoc_name: ast::Name) |
| -> bool |
| { |
| let item = match ccx.tcx.map.get(trait_node_id) { |
| hir_map::NodeItem(item) => item, |
| _ => bug!("trait_node_id {} is not an item", trait_node_id) |
| }; |
| |
| let trait_items = match item.node { |
| hir::ItemTrait(_, _, _, ref trait_items) => trait_items, |
| _ => bug!("trait_node_id {} is not a trait", trait_node_id) |
| }; |
| |
| trait_items.iter().any(|trait_item| { |
| match trait_item.node { |
| hir::TypeTraitItem(..) => trait_item.name == assoc_name, |
| _ => false, |
| } |
| }) |
| } |
| |
| fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) { |
| let tcx = ccx.tcx; |
| let trait_def = trait_def_of_item(ccx, it); |
| |
| let def_id = ccx.tcx.map.local_def_id(it.id); |
| |
| let (generics, items) = match it.node { |
| hir::ItemTrait(_, ref generics, _, ref items) => (generics, items), |
| ref s => { |
| span_bug!( |
| it.span, |
| "trait_def_of_item invoked on {:?}", |
| s); |
| } |
| }; |
| |
| let super_predicates = ccx.tcx.lookup_super_predicates(def_id); |
| |
| // `ty_generic_predicates` below will consider the bounds on the type |
| // parameters (including `Self`) and the explicit where-clauses, |
| // but to get the full set of predicates on a trait we need to add |
| // in the supertrait bounds and anything declared on the |
| // associated types. |
| let mut base_predicates = super_predicates; |
| |
| // Add in a predicate that `Self:Trait` (where `Trait` is the |
| // current trait). This is needed for builtin bounds. |
| let self_predicate = trait_def.trait_ref.to_poly_trait_ref().to_predicate(); |
| base_predicates.predicates.push(SelfSpace, self_predicate); |
| |
| // add in the explicit where-clauses |
| let mut trait_predicates = |
| ty_generic_predicates(ccx, TypeSpace, generics, &base_predicates); |
| |
| let assoc_predicates = predicates_for_associated_types(ccx, |
| generics, |
| &trait_predicates, |
| trait_def.trait_ref, |
| items); |
| trait_predicates.predicates.extend(TypeSpace, assoc_predicates.into_iter()); |
| |
| let prev_predicates = tcx.predicates.borrow_mut().insert(def_id, trait_predicates); |
| assert!(prev_predicates.is_none()); |
| |
| return; |
| |
| fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| ast_generics: &hir::Generics, |
| trait_predicates: &ty::GenericPredicates<'tcx>, |
| self_trait_ref: ty::TraitRef<'tcx>, |
| trait_items: &[hir::TraitItem]) |
| -> Vec<ty::Predicate<'tcx>> |
| { |
| trait_items.iter().flat_map(|trait_item| { |
| let bounds = match trait_item.node { |
| hir::TypeTraitItem(ref bounds, _) => bounds, |
| _ => { |
| return vec!().into_iter(); |
| } |
| }; |
| |
| let assoc_ty = ccx.tcx.mk_projection(self_trait_ref, |
| trait_item.name); |
| |
| let bounds = compute_bounds(&ccx.icx(&(ast_generics, trait_predicates)), |
| assoc_ty, |
| bounds, |
| SizedByDefault::Yes, |
| trait_item.span); |
| |
| bounds.predicates(ccx.tcx, assoc_ty).into_iter() |
| }).collect() |
| } |
| } |
| |
| fn type_scheme_of_def_id<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| def_id: DefId) |
| -> ty::TypeScheme<'tcx> |
| { |
| if let Some(node_id) = ccx.tcx.map.as_local_node_id(def_id) { |
| match ccx.tcx.map.find(node_id) { |
| Some(hir_map::NodeItem(item)) => { |
| type_scheme_of_item(ccx, &item) |
| } |
| Some(hir_map::NodeForeignItem(foreign_item)) => { |
| let abi = ccx.tcx.map.get_foreign_abi(node_id); |
| type_scheme_of_foreign_item(ccx, &foreign_item, abi) |
| } |
| x => { |
| bug!("unexpected sort of node in get_item_type_scheme(): {:?}", |
| x); |
| } |
| } |
| } else { |
| ccx.tcx.lookup_item_type(def_id) |
| } |
| } |
| |
| fn type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| item: &hir::Item) |
| -> ty::TypeScheme<'tcx> |
| { |
| let item_def_id = ccx.tcx.map.local_def_id(item.id); |
| ccx.tcx.tcache.memoize(item_def_id, || { |
| // NB. Since the `memoized` function enters a new task, and we |
| // are giving this task access to the item `item`, we must |
| // register a read. |
| ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); |
| compute_type_scheme_of_item(ccx, item) |
| }) |
| } |
| |
| fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| it: &hir::Item) |
| -> ty::TypeScheme<'tcx> |
| { |
| let tcx = ccx.tcx; |
| match it.node { |
| hir::ItemStatic(ref t, _, _) | hir::ItemConst(ref t, _) => { |
| let ty = ccx.icx(&()).to_ty(&ExplicitRscope, &t); |
| ty::TypeScheme { ty: ty, generics: ty::Generics::empty() } |
| } |
| hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { |
| let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty()); |
| let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl); |
| let def_id = ccx.tcx.map.local_def_id(it.id); |
| let substs = mk_item_substs(ccx, &ty_generics); |
| let ty = tcx.mk_fn_def(def_id, substs, tofd); |
| ty::TypeScheme { ty: ty, generics: ty_generics } |
| } |
| hir::ItemTy(ref t, ref generics) => { |
| let ty_generics = ty_generics_for_type(ccx, generics); |
| let ty = ccx.icx(generics).to_ty(&ExplicitRscope, &t); |
| ty::TypeScheme { ty: ty, generics: ty_generics } |
| } |
| hir::ItemEnum(ref ei, ref generics) => { |
| let def = convert_enum_def(ccx, it, ei); |
| let ty_generics = ty_generics_for_type(ccx, generics); |
| let substs = mk_item_substs(ccx, &ty_generics); |
| let t = tcx.mk_enum(def, substs); |
| ty::TypeScheme { ty: t, generics: ty_generics } |
| } |
| hir::ItemStruct(ref si, ref generics) => { |
| let def = convert_struct_def(ccx, it, si); |
| let ty_generics = ty_generics_for_type(ccx, generics); |
| let substs = mk_item_substs(ccx, &ty_generics); |
| let t = tcx.mk_struct(def, substs); |
| ty::TypeScheme { ty: t, generics: ty_generics } |
| } |
| hir::ItemDefaultImpl(..) | |
| hir::ItemTrait(..) | |
| hir::ItemImpl(..) | |
| hir::ItemMod(..) | |
| hir::ItemForeignMod(..) | |
| hir::ItemExternCrate(..) | |
| hir::ItemUse(..) => { |
| span_bug!( |
| it.span, |
| "compute_type_scheme_of_item: unexpected item type: {:?}", |
| it.node); |
| } |
| } |
| } |
| |
| fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| it: &hir::Item) |
| -> (ty::TypeScheme<'tcx>, ty::GenericPredicates<'tcx>) |
| { |
| let tcx = ccx.tcx; |
| |
| let tag = type_scheme_of_item(ccx, it); |
| let scheme = TypeScheme { generics: tag.generics, ty: tag.ty }; |
| let predicates = match it.node { |
| hir::ItemStatic(..) | hir::ItemConst(..) => { |
| ty::GenericPredicates::empty() |
| } |
| hir::ItemFn(_, _, _, _, ref ast_generics, _) => { |
| ty_generic_predicates_for_fn(ccx, ast_generics, &ty::GenericPredicates::empty()) |
| } |
| hir::ItemTy(_, ref generics) => { |
| ty_generic_predicates_for_type_or_impl(ccx, generics) |
| } |
| hir::ItemEnum(_, ref generics) => { |
| ty_generic_predicates_for_type_or_impl(ccx, generics) |
| } |
| hir::ItemStruct(_, ref generics) => { |
| ty_generic_predicates_for_type_or_impl(ccx, generics) |
| } |
| hir::ItemDefaultImpl(..) | |
| hir::ItemTrait(..) | |
| hir::ItemExternCrate(..) | |
| hir::ItemUse(..) | |
| hir::ItemImpl(..) | |
| hir::ItemMod(..) | |
| hir::ItemForeignMod(..) => { |
| span_bug!( |
| it.span, |
| "compute_type_scheme_of_item: unexpected item type: {:?}", |
| it.node); |
| } |
| }; |
| |
| let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), |
| predicates.clone()); |
| assert!(prev_predicates.is_none()); |
| |
| // Debugging aid. |
| if tcx.has_attr(ccx.tcx.map.local_def_id(it.id), "rustc_object_lifetime_default") { |
| let object_lifetime_default_reprs: String = |
| scheme.generics.types.iter() |
| .map(|t| match t.object_lifetime_default { |
| ty::ObjectLifetimeDefault::Specific(r) => r.to_string(), |
| d => format!("{:?}", d), |
| }) |
| .collect::<Vec<String>>() |
| .join(","); |
| |
| tcx.sess.span_err(it.span, &object_lifetime_default_reprs); |
| } |
| |
| return (scheme, predicates); |
| } |
| |
| fn type_scheme_of_foreign_item<'a, 'tcx>( |
| ccx: &CrateCtxt<'a, 'tcx>, |
| item: &hir::ForeignItem, |
| abi: abi::Abi) |
| -> ty::TypeScheme<'tcx> |
| { |
| let item_def_id = ccx.tcx.map.local_def_id(item.id); |
| ccx.tcx.tcache.memoize(item_def_id, || { |
| // NB. Since the `memoized` function enters a new task, and we |
| // are giving this task access to the item `item`, we must |
| // register a read. |
| ccx.tcx.dep_graph.read(DepNode::Hir(item_def_id)); |
| compute_type_scheme_of_foreign_item(ccx, item, abi) |
| }) |
| } |
| |
| fn compute_type_scheme_of_foreign_item<'a, 'tcx>( |
| ccx: &CrateCtxt<'a, 'tcx>, |
| it: &hir::ForeignItem, |
| abi: abi::Abi) |
| -> ty::TypeScheme<'tcx> |
| { |
| match it.node { |
| hir::ForeignItemFn(ref fn_decl, ref generics) => { |
| compute_type_scheme_of_foreign_fn_decl( |
| ccx, ccx.tcx.map.local_def_id(it.id), |
| fn_decl, generics, abi) |
| } |
| hir::ForeignItemStatic(ref t, _) => { |
| ty::TypeScheme { |
| generics: ty::Generics::empty(), |
| ty: AstConv::ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, t) |
| } |
| } |
| } |
| } |
| |
| fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| it: &hir::ForeignItem) |
| { |
| // For reasons I cannot fully articulate, I do so hate the AST |
| // map, and I regard each time that I use it as a personal and |
| // moral failing, but at the moment it seems like the only |
| // convenient way to extract the ABI. - ndm |
| let tcx = ccx.tcx; |
| let abi = tcx.map.get_foreign_abi(it.id); |
| |
| let scheme = type_scheme_of_foreign_item(ccx, it, abi); |
| write_ty_to_tcx(ccx, it.id, scheme.ty); |
| |
| let predicates = match it.node { |
| hir::ForeignItemFn(_, ref generics) => { |
| ty_generic_predicates_for_fn(ccx, generics, &ty::GenericPredicates::empty()) |
| } |
| hir::ForeignItemStatic(..) => { |
| ty::GenericPredicates::empty() |
| } |
| }; |
| |
| let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), |
| predicates); |
| assert!(prev_predicates.is_none()); |
| } |
| |
| fn ty_generics_for_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics: &hir::Generics) |
| -> ty::Generics<'tcx> { |
| ty_generics(ccx, TypeSpace, generics, &ty::Generics::empty(), true) |
| } |
| |
| fn ty_generics_for_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics: &hir::Generics) |
| -> ty::Generics<'tcx> { |
| ty_generics(ccx, TypeSpace, generics, &ty::Generics::empty(), false) |
| } |
| |
| fn ty_generic_predicates_for_type_or_impl<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| generics: &hir::Generics) |
| -> ty::GenericPredicates<'tcx> |
| { |
| ty_generic_predicates(ccx, TypeSpace, generics, &ty::GenericPredicates::empty()) |
| } |
| |
| fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| trait_id: ast::NodeId, |
| substs: &'tcx Substs<'tcx>, |
| ast_generics: &hir::Generics) |
| -> ty::Generics<'tcx> |
| { |
| debug!("ty_generics_for_trait(trait_id={:?}, substs={:?})", |
| ccx.tcx.map.local_def_id(trait_id), substs); |
| |
| let mut generics = ty_generics_for_type(ccx, ast_generics); |
| |
| // Add in the self type parameter. |
| // |
| // Something of a hack: use the node id for the trait, also as |
| // the node id for the Self type parameter. |
| let param_id = trait_id; |
| |
| let parent = ccx.tcx.map.get_parent(param_id); |
| |
| let def = ty::TypeParameterDef { |
| space: SelfSpace, |
| index: 0, |
| name: keywords::SelfType.name(), |
| def_id: ccx.tcx.map.local_def_id(param_id), |
| default_def_id: ccx.tcx.map.local_def_id(parent), |
| default: None, |
| object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault, |
| }; |
| |
| ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone()); |
| |
| generics.types.push(SelfSpace, def); |
| |
| return generics; |
| } |
| |
| fn ty_generics_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| generics: &hir::Generics, |
| base_generics: &ty::Generics<'tcx>) |
| -> ty::Generics<'tcx> |
| { |
| ty_generics(ccx, FnSpace, generics, base_generics, false) |
| } |
| |
| fn ty_generic_predicates_for_fn<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| generics: &hir::Generics, |
| base_predicates: &ty::GenericPredicates<'tcx>) |
| -> ty::GenericPredicates<'tcx> |
| { |
| ty_generic_predicates(ccx, FnSpace, generics, base_predicates) |
| } |
| |
| // Add the Sized bound, unless the type parameter is marked as `?Sized`. |
| fn add_unsized_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, |
| bounds: &mut ty::BuiltinBounds, |
| ast_bounds: &[hir::TyParamBound], |
| span: Span) |
| { |
| let tcx = astconv.tcx(); |
| |
| // Try to find an unbound in bounds. |
| let mut unbound = None; |
| for ab in ast_bounds { |
| if let &hir::TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = ab { |
| if unbound.is_none() { |
| assert!(ptr.bound_lifetimes.is_empty()); |
| unbound = Some(ptr.trait_ref.clone()); |
| } else { |
| span_err!(tcx.sess, span, E0203, |
| "type parameter has more than one relaxed default \ |
| bound, only one is supported"); |
| } |
| } |
| } |
| |
| let kind_id = tcx.lang_items.require(SizedTraitLangItem); |
| match unbound { |
| Some(ref tpb) => { |
| // FIXME(#8559) currently requires the unbound to be built-in. |
| let trait_def_id = tcx.expect_def(tpb.ref_id).def_id(); |
| match kind_id { |
| Ok(kind_id) if trait_def_id != kind_id => { |
| tcx.sess.span_warn(span, |
| "default bound relaxed for a type parameter, but \ |
| this does nothing because the given bound is not \ |
| a default. Only `?Sized` is supported"); |
| tcx.try_add_builtin_trait(kind_id, bounds); |
| } |
| _ => {} |
| } |
| } |
| _ if kind_id.is_ok() => { |
| tcx.try_add_builtin_trait(kind_id.unwrap(), bounds); |
| } |
| // No lang item for Sized, so we can't add it as a bound. |
| None => {} |
| } |
| } |
| |
| /// Returns the early-bound lifetimes declared in this generics |
| /// listing. For anything other than fns/methods, this is just all |
| /// the lifetimes that are declared. For fns or methods, we have to |
| /// screen out those that do not appear in any where-clauses etc using |
| /// `resolve_lifetime::early_bound_lifetimes`. |
| fn early_bound_lifetimes_from_generics<'a, 'tcx, 'hir>( |
| ccx: &CrateCtxt<'a, 'tcx>, |
| ast_generics: &'hir hir::Generics) |
| -> Vec<&'hir hir::LifetimeDef> |
| { |
| ast_generics |
| .lifetimes |
| .iter() |
| .filter(|l| !ccx.tcx.named_region_map.late_bound.contains_key(&l.lifetime.id)) |
| .collect() |
| } |
| |
| fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| space: ParamSpace, |
| ast_generics: &hir::Generics, |
| base_predicates: &ty::GenericPredicates<'tcx>) |
| -> ty::GenericPredicates<'tcx> |
| { |
| let tcx = ccx.tcx; |
| let mut result = base_predicates.clone(); |
| |
| // Collect the predicates that were written inline by the user on each |
| // type parameter (e.g., `<T:Foo>`). |
| for (index, param) in ast_generics.ty_params.iter().enumerate() { |
| let index = index as u32; |
| let param_ty = ty::ParamTy::new(space, index, param.name).to_ty(ccx.tcx); |
| let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)), |
| param_ty, |
| ¶m.bounds, |
| SizedByDefault::Yes, |
| param.span); |
| let predicates = bounds.predicates(ccx.tcx, param_ty); |
| result.predicates.extend(space, predicates.into_iter()); |
| } |
| |
| // Collect the region predicates that were declared inline as |
| // well. In the case of parameters declared on a fn or method, we |
| // have to be careful to only iterate over early-bound regions. |
| let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics); |
| for (index, param) in early_lifetimes.iter().enumerate() { |
| let index = index as u32; |
| let region = |
| ty::ReEarlyBound(ty::EarlyBoundRegion { |
| space: space, |
| index: index, |
| name: param.lifetime.name |
| }); |
| for bound in ¶m.bounds { |
| let bound_region = ast_region_to_region(ccx.tcx, bound); |
| let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); |
| result.predicates.push(space, outlives.to_predicate()); |
| } |
| } |
| |
| // Add in the bounds that appear in the where-clause |
| let where_clause = &ast_generics.where_clause; |
| for predicate in &where_clause.predicates { |
| match predicate { |
| &hir::WherePredicate::BoundPredicate(ref bound_pred) => { |
| let ty = AstConv::ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)), |
| &ExplicitRscope, |
| &bound_pred.bounded_ty); |
| |
| for bound in bound_pred.bounds.iter() { |
| match bound { |
| &hir::TyParamBound::TraitTyParamBound(ref poly_trait_ref, _) => { |
| let mut projections = Vec::new(); |
| |
| let trait_ref = |
| conv_poly_trait_ref(&ccx.icx(&(base_predicates, ast_generics)), |
| ty, |
| poly_trait_ref, |
| &mut projections); |
| |
| result.predicates.push(space, trait_ref.to_predicate()); |
| |
| for projection in &projections { |
| result.predicates.push(space, projection.to_predicate()); |
| } |
| } |
| |
| &hir::TyParamBound::RegionTyParamBound(ref lifetime) => { |
| let region = ast_region_to_region(tcx, lifetime); |
| let pred = ty::Binder(ty::OutlivesPredicate(ty, region)); |
| result.predicates.push(space, ty::Predicate::TypeOutlives(pred)) |
| } |
| } |
| } |
| } |
| |
| &hir::WherePredicate::RegionPredicate(ref region_pred) => { |
| let r1 = ast_region_to_region(tcx, ®ion_pred.lifetime); |
| for bound in ®ion_pred.bounds { |
| let r2 = ast_region_to_region(tcx, bound); |
| let pred = ty::Binder(ty::OutlivesPredicate(r1, r2)); |
| result.predicates.push(space, ty::Predicate::RegionOutlives(pred)) |
| } |
| } |
| |
| &hir::WherePredicate::EqPredicate(ref eq_pred) => { |
| // FIXME(#20041) |
| span_bug!(eq_pred.span, |
| "Equality constraints are not yet \ |
| implemented (#20041)") |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| fn ty_generics<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| space: ParamSpace, |
| ast_generics: &hir::Generics, |
| base_generics: &ty::Generics<'tcx>, |
| allow_defaults: bool) |
| -> ty::Generics<'tcx> |
| { |
| let tcx = ccx.tcx; |
| let mut result = base_generics.clone(); |
| |
| let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics); |
| for (i, l) in early_lifetimes.iter().enumerate() { |
| let bounds = l.bounds.iter() |
| .map(|l| ast_region_to_region(tcx, l)) |
| .collect(); |
| let def = ty::RegionParameterDef { name: l.lifetime.name, |
| space: space, |
| index: i as u32, |
| def_id: ccx.tcx.map.local_def_id(l.lifetime.id), |
| bounds: bounds }; |
| result.regions.push(space, def); |
| } |
| |
| assert!(result.types.is_empty_in(space)); |
| |
| // Now create the real type parameters. |
| for i in 0..ast_generics.ty_params.len() { |
| let def = |
| get_or_create_type_parameter_def(ccx, ast_generics, space, i as u32, allow_defaults); |
| debug!("ty_generics: def for type param: {:?}, {:?}", def, space); |
| result.types.push(space, def); |
| } |
| |
| result |
| } |
| |
| fn convert_default_type_parameter<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| path: &P<hir::Ty>, |
| space: ParamSpace, |
| index: u32) |
| -> Ty<'tcx> |
| { |
| let ty = AstConv::ast_ty_to_ty(&ccx.icx(&()), &ExplicitRscope, &path); |
| |
| for leaf_ty in ty.walk() { |
| if let ty::TyParam(p) = leaf_ty.sty { |
| if p.space == space && p.idx >= index { |
| span_err!(ccx.tcx.sess, path.span, E0128, |
| "type parameters with a default cannot use \ |
| forward declared identifiers"); |
| |
| return ccx.tcx.types.err |
| } |
| } |
| } |
| |
| ty |
| } |
| |
| fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| ast_generics: &hir::Generics, |
| space: ParamSpace, |
| index: u32, |
| allow_defaults: bool) |
| -> ty::TypeParameterDef<'tcx> |
| { |
| let param = &ast_generics.ty_params[index as usize]; |
| |
| let tcx = ccx.tcx; |
| match tcx.ty_param_defs.borrow().get(¶m.id) { |
| Some(d) => { return d.clone(); } |
| None => { } |
| } |
| |
| let default = param.default.as_ref().map( |
| |def| convert_default_type_parameter(ccx, def, space, index) |
| ); |
| |
| let object_lifetime_default = |
| compute_object_lifetime_default(ccx, param.id, |
| ¶m.bounds, &ast_generics.where_clause); |
| |
| let parent = tcx.map.get_parent(param.id); |
| |
| if !allow_defaults && default.is_some() { |
| if !tcx.sess.features.borrow().default_type_parameter_fallback { |
| tcx.sess.add_lint( |
| lint::builtin::INVALID_TYPE_PARAM_DEFAULT, |
| param.id, |
| param.span, |
| format!("defaults for type parameters are only allowed in `struct`, \ |
| `enum`, `type`, or `trait` definitions.")); |
| } |
| } |
| |
| let def = ty::TypeParameterDef { |
| space: space, |
| index: index, |
| name: param.name, |
| def_id: ccx.tcx.map.local_def_id(param.id), |
| default_def_id: ccx.tcx.map.local_def_id(parent), |
| default: default, |
| object_lifetime_default: object_lifetime_default, |
| }; |
| |
| tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone()); |
| |
| def |
| } |
| |
| /// Scan the bounds and where-clauses on a parameter to extract bounds |
| /// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`. |
| /// This runs as part of computing the minimal type scheme, so we |
| /// intentionally avoid just asking astconv to convert all the where |
| /// clauses into a `ty::Predicate`. This is because that could induce |
| /// artificial cycles. |
| fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| param_id: ast::NodeId, |
| param_bounds: &[hir::TyParamBound], |
| where_clause: &hir::WhereClause) |
| -> ty::ObjectLifetimeDefault |
| { |
| let inline_bounds = from_bounds(ccx, param_bounds); |
| let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates); |
| let all_bounds: HashSet<_> = inline_bounds.into_iter() |
| .chain(where_bounds) |
| .collect(); |
| return if all_bounds.len() > 1 { |
| ty::ObjectLifetimeDefault::Ambiguous |
| } else if all_bounds.len() == 0 { |
| ty::ObjectLifetimeDefault::BaseDefault |
| } else { |
| ty::ObjectLifetimeDefault::Specific( |
| all_bounds.into_iter().next().unwrap()) |
| }; |
| |
| fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| bounds: &[hir::TyParamBound]) |
| -> Vec<ty::Region> |
| { |
| bounds.iter() |
| .filter_map(|bound| { |
| match *bound { |
| hir::TraitTyParamBound(..) => |
| None, |
| hir::RegionTyParamBound(ref lifetime) => |
| Some(ast_region_to_region(ccx.tcx, lifetime)), |
| } |
| }) |
| .collect() |
| } |
| |
| fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, |
| param_id: ast::NodeId, |
| predicates: &[hir::WherePredicate]) |
| -> Vec<ty::Region> |
| { |
| predicates.iter() |
| .flat_map(|predicate| { |
| match *predicate { |
| hir::WherePredicate::BoundPredicate(ref data) => { |
| if data.bound_lifetimes.is_empty() && |
| is_param(ccx.tcx, &data.bounded_ty, param_id) |
| { |
| from_bounds(ccx, &data.bounds).into_iter() |
| } else { |
| Vec::new().into_iter() |
| } |
| } |
| hir::WherePredicate::RegionPredicate(..) | |
| hir::WherePredicate::EqPredicate(..) => { |
| Vec::new().into_iter() |
| } |
| } |
| }) |
| .collect() |
| } |
| } |
| |
| enum SizedByDefault { Yes, No, } |
| |
| /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or |
| /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the |
| /// built-in trait (formerly known as kind): Send. |
| fn compute_bounds<'tcx>(astconv: &AstConv<'tcx, 'tcx>, |
| param_ty: ty::Ty<'tcx>, |
| ast_bounds: &[hir::TyParamBound], |
| sized_by_default: SizedByDefault, |
| span: Span) |
| -> Bounds<'tcx> |
| { |
| let mut bounds = |
| conv_param_bounds(astconv, |
| span, |
| param_ty, |
| ast_bounds); |
| |
| if let SizedByDefault::Yes = sized_by_default { |
| add_unsized_bound(astconv, |
| &mut bounds.builtin_bounds, |
| ast_bounds, |
| span); |
| } |
| |
| bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); |
| |
| bounds |
| } |
| |
| /// Converts a specific TyParamBound from the AST into a set of |
| /// predicates that apply to the self-type. A vector is returned |
| /// because this can be anywhere from 0 predicates (`T:?Sized` adds no |
| /// predicates) to 1 (`T:Foo`) to many (`T:Bar<X=i32>` adds `T:Bar` |
| /// and `<T as Bar>::X == i32`). |
| fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, |
| param_ty: Ty<'tcx>, |
| bound: &hir::TyParamBound) |
| -> Vec<ty::Predicate<'tcx>> |
| { |
| match *bound { |
| hir::TraitTyParamBound(ref tr, hir::TraitBoundModifier::None) => { |
| let mut projections = Vec::new(); |
| let pred = conv_poly_trait_ref(astconv, param_ty, tr, &mut projections); |
| projections.into_iter() |
| .map(|p| p.to_predicate()) |
| .chain(Some(pred.to_predicate())) |
| .collect() |
| } |
| hir::RegionTyParamBound(ref lifetime) => { |
| let region = ast_region_to_region(astconv.tcx(), lifetime); |
| let pred = ty::Binder(ty::OutlivesPredicate(param_ty, region)); |
| vec![ty::Predicate::TypeOutlives(pred)] |
| } |
| hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => { |
| Vec::new() |
| } |
| } |
| } |
| |
| fn conv_poly_trait_ref<'tcx>(astconv: &AstConv<'tcx, 'tcx>, |
| param_ty: Ty<'tcx>, |
| trait_ref: &hir::PolyTraitRef, |
| projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>) |
| -> ty::PolyTraitRef<'tcx> |
| { |
| AstConv::instantiate_poly_trait_ref(astconv, |
| &ExplicitRscope, |
| trait_ref, |
| Some(param_ty), |
| projections) |
| } |
| |
| fn conv_param_bounds<'a,'tcx>(astconv: &AstConv<'tcx, 'tcx>, |
| span: Span, |
| param_ty: ty::Ty<'tcx>, |
| ast_bounds: &[hir::TyParamBound]) |
| -> Bounds<'tcx> |
| { |
| let tcx = astconv.tcx(); |
| let PartitionedBounds { |
| builtin_bounds, |
| trait_bounds, |
| region_bounds |
| } = partition_bounds(tcx, span, &ast_bounds); |
| |
| let mut projection_bounds = Vec::new(); |
| |
| let trait_bounds: Vec<ty::PolyTraitRef> = |
| trait_bounds.iter() |
| .map(|bound| conv_poly_trait_ref(astconv, |
| param_ty, |
| *bound, |
| &mut projection_bounds)) |
| .collect(); |
| |
| let region_bounds: Vec<ty::Region> = |
| region_bounds.into_iter() |
| .map(|r| ast_region_to_region(tcx, r)) |
| .collect(); |
| |
| Bounds { |
| region_bounds: region_bounds, |
| builtin_bounds: builtin_bounds, |
| trait_bounds: trait_bounds, |
| projection_bounds: projection_bounds, |
| } |
| } |
| |
| fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( |
| ccx: &CrateCtxt<'a, 'tcx>, |
| id: DefId, |
| decl: &hir::FnDecl, |
| ast_generics: &hir::Generics, |
| abi: abi::Abi) |
| -> ty::TypeScheme<'tcx> |
| { |
| let ty_generics = ty_generics_for_fn(ccx, ast_generics, &ty::Generics::empty()); |
| |
| let rb = BindingRscope::new(); |
| let input_tys = decl.inputs |
| .iter() |
| .map(|a| AstConv::ty_of_arg(&ccx.icx(ast_generics), &rb, a, None)) |
| .collect::<Vec<_>>(); |
| |
| let output = match decl.output { |
| hir::Return(ref ty) => |
| ty::FnConverging(AstConv::ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &ty)), |
| hir::DefaultReturn(..) => |
| ty::FnConverging(ccx.tcx.mk_nil()), |
| hir::NoReturn(..) => |
| ty::FnDiverging |
| }; |
| |
| // feature gate SIMD types in FFI, since I (huonw) am not sure the |
| // ABIs are handled at all correctly. |
| if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic |
| && !ccx.tcx.sess.features.borrow().simd_ffi { |
| let check = |ast_ty: &hir::Ty, ty: ty::Ty| { |
| if ty.is_simd() { |
| ccx.tcx.sess.struct_span_err(ast_ty.span, |
| &format!("use of SIMD type `{}` in FFI is highly experimental and \ |
| may result in invalid code", |
| pprust::ty_to_string(ast_ty))) |
| .help("add #![feature(simd_ffi)] to the crate attributes to enable") |
| .emit(); |
| } |
| }; |
| for (input, ty) in decl.inputs.iter().zip(&input_tys) { |
| check(&input.ty, ty) |
| } |
| if let hir::Return(ref ty) = decl.output { |
| check(&ty, output.unwrap()) |
| } |
| } |
| |
| let substs = mk_item_substs(ccx, &ty_generics); |
| let t_fn = ccx.tcx.mk_fn_def(id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy { |
| abi: abi, |
| unsafety: hir::Unsafety::Unsafe, |
| sig: ty::Binder(ty::FnSig {inputs: input_tys, |
| output: output, |
| variadic: decl.variadic}), |
| })); |
| |
| ty::TypeScheme { |
| generics: ty_generics, |
| ty: t_fn |
| } |
| } |
| |
| fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| ty_generics: &ty::Generics<'tcx>) |
| -> &'tcx Substs<'tcx> |
| { |
| let types = |
| ty_generics.types.map( |
| |def| ccx.tcx.mk_param_from_def(def)); |
| |
| let regions = |
| ty_generics.regions.map( |
| |def| def.to_early_bound_region()); |
| |
| ccx.tcx.mk_substs(Substs::new(types, regions)) |
| } |
| |
| /// Checks that all the type parameters on an impl |
| fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| ast_generics: &hir::Generics, |
| impl_predicates: &mut ty::GenericPredicates<'tcx>, |
| impl_def_id: DefId) |
| { |
| let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); |
| let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); |
| |
| assert!(impl_predicates.predicates.is_empty_in(FnSpace)); |
| assert!(impl_predicates.predicates.is_empty_in(SelfSpace)); |
| |
| // The trait reference is an input, so find all type parameters |
| // reachable from there, to start (if this is an inherent impl, |
| // then just examine the self type). |
| let mut input_parameters: HashSet<_> = |
| ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); |
| if let Some(ref trait_ref) = impl_trait_ref { |
| input_parameters.extend(ctp::parameters_for(trait_ref, false)); |
| } |
| |
| ctp::setup_constraining_predicates(impl_predicates.predicates.get_mut_slice(TypeSpace), |
| impl_trait_ref, |
| &mut input_parameters); |
| |
| for (index, ty_param) in ast_generics.ty_params.iter().enumerate() { |
| let param_ty = ty::ParamTy { space: TypeSpace, |
| idx: index as u32, |
| name: ty_param.name }; |
| if !input_parameters.contains(&ctp::Parameter::Type(param_ty)) { |
| report_unused_parameter(ccx, ty_param.span, "type", ¶m_ty.to_string()); |
| } |
| } |
| } |
| |
| fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, |
| ast_generics: &hir::Generics, |
| impl_def_id: DefId, |
| impl_items: &[hir::ImplItem]) |
| { |
| // Every lifetime used in an associated type must be constrained. |
| let impl_scheme = ccx.tcx.lookup_item_type(impl_def_id); |
| let impl_predicates = ccx.tcx.lookup_predicates(impl_def_id); |
| let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id); |
| |
| let mut input_parameters: HashSet<_> = |
| ctp::parameters_for(&impl_scheme.ty, false).into_iter().collect(); |
| if let Some(ref trait_ref) = impl_trait_ref { |
| input_parameters.extend(ctp::parameters_for(trait_ref, false)); |
| } |
| ctp::identify_constrained_type_params( |
| &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); |
| |
| let lifetimes_in_associated_types: HashSet<_> = impl_items.iter() |
| .map(|item| ccx.tcx.impl_or_trait_item(ccx.tcx.map.local_def_id(item.id))) |
| .filter_map(|item| match item { |
| ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty, |
| ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None |
| }) |
| .flat_map(|ty| ctp::parameters_for(&ty, true)) |
| .filter_map(|p| match p { |
| ctp::Parameter::Type(_) => None, |
| ctp::Parameter::Region(r) => Some(r), |
| }) |
| .collect(); |
| |
| for (index, lifetime_def) in ast_generics.lifetimes.iter().enumerate() { |
| let region = ty::EarlyBoundRegion { space: TypeSpace, |
| index: index as u32, |
| name: lifetime_def.lifetime.name }; |
| if |
| lifetimes_in_associated_types.contains(®ion) && // (*) |
| !input_parameters.contains(&ctp::Parameter::Region(region)) |
| { |
| report_unused_parameter(ccx, lifetime_def.lifetime.span, |
| "lifetime", ®ion.name.to_string()); |
| } |
| } |
| |
| // (*) This is a horrible concession to reality. I think it'd be |
| // better to just ban unconstrianed lifetimes outright, but in |
| // practice people do non-hygenic macros like: |
| // |
| // ``` |
| // macro_rules! __impl_slice_eq1 { |
| // ($Lhs: ty, $Rhs: ty, $Bound: ident) => { |
| // impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> { |
| // .... |
| // } |
| // } |
| // } |
| // ``` |
| // |
| // In a concession to backwards compatbility, we continue to |
| // permit those, so long as the lifetimes aren't used in |
| // associated types. I believe this is sound, because lifetimes |
| // used elsewhere are not projected back out. |
| } |
| |
| fn report_unused_parameter(ccx: &CrateCtxt, |
| span: Span, |
| kind: &str, |
| name: &str) |
| { |
| span_err!(ccx.tcx.sess, span, E0207, |
| "the {} parameter `{}` is not constrained by the \ |
| impl trait, self type, or predicates", |
| kind, name); |
| } |