diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index aa74fb2e02f..76c73f12f4e 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -832,7 +832,10 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, constrained_by_input.visit_ty(&arg.ty); } - let mut appears_in_output = AllCollector { regions: FnvHashSet() }; + let mut appears_in_output = AllCollector { + regions: FnvHashSet(), + impl_trait: false + }; intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output); debug!("insert_late_bound_lifetimes: constrained_by_input={:?}", @@ -842,7 +845,10 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, // // Subtle point: because we disallow nested bindings, we can just // ignore binders here and scrape up all names we see. - let mut appears_in_where_clause = AllCollector { regions: FnvHashSet() }; + let mut appears_in_where_clause = AllCollector { + regions: FnvHashSet(), + impl_trait: false + }; for ty_param in generics.ty_params.iter() { walk_list!(&mut appears_in_where_clause, visit_ty_param_bound, @@ -864,12 +870,16 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, // Late bound regions are those that: // - appear in the inputs // - do not appear in the where-clauses + // - are not implicitly captured by `impl Trait` for lifetime in &generics.lifetimes { let name = lifetime.lifetime.name; // appears in the where clauses? early-bound. if appears_in_where_clause.regions.contains(&name) { continue; } + // any `impl Trait` in the return type? early-bound. + if appears_in_output.impl_trait { continue; } + // does not appear in the inputs, but appears in the return // type? eventually this will be early-bound, but for now we // just mark it so we can issue warnings. @@ -932,12 +942,20 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap, struct AllCollector { regions: FnvHashSet, + impl_trait: bool } impl<'v> Visitor<'v> for AllCollector { fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { self.regions.insert(lifetime_ref.name); } + + fn visit_ty(&mut self, ty: &hir::Ty) { + if let hir::TyImplTrait(_) = ty.node { + self.impl_trait = true; + } + intravisit::walk_ty(self, ty); + } } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f1d2bdb0117..57e58a98b53 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -65,6 +65,7 @@ use require_c_abi_if_variadic; use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope, ElisionFailureInfo, ElidedLifetime}; +use rscope::{AnonTypeScope, MaybeWithAnonTypes}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::{NodeMap, FnvHashSet}; @@ -635,20 +636,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn convert_ty_with_lifetime_elision(&self, elided_lifetime: ElidedLifetime, - ty: &hir::Ty) + ty: &hir::Ty, + anon_scope: Option) -> Ty<'tcx> { match elided_lifetime { Ok(implied_output_region) => { let rb = ElidableRscope::new(implied_output_region); - self.ast_ty_to_ty(&rb, ty) + self.ast_ty_to_ty(&MaybeWithAnonTypes::new(rb, anon_scope), ty) } Err(param_lifetimes) => { // All regions must be explicitly specified in the output // if the lifetime elision rules do not apply. This saves // the user from potentially-confusing errors. let rb = UnelidableRscope::new(param_lifetimes); - self.ast_ty_to_ty(&rb, ty) + self.ast_ty_to_ty(&MaybeWithAnonTypes::new(rb, anon_scope), ty) } } } @@ -665,7 +667,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let region_substs = self.create_region_substs(rscope, span, decl_generics, Vec::new()); - let binding_rscope = BindingRscope::new(); + let anon_scope = rscope.anon_type_scope(); + let binding_rscope = MaybeWithAnonTypes::new(BindingRscope::new(), anon_scope); let inputs = data.inputs.iter() .map(|a_t| self.ast_ty_arg_to_ty(&binding_rscope, decl_generics, @@ -679,7 +682,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let (output, output_span) = match data.output { Some(ref output_ty) => { - (self.convert_ty_with_lifetime_elision(implied_output_region, &output_ty), + (self.convert_ty_with_lifetime_elision(implied_output_region, + &output_ty, + anon_scope), output_ty.span) } None => { @@ -1703,7 +1708,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } hir::TyBareFn(ref bf) => { require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); - let bare_fn_ty = self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl); + let anon_scope = rscope.anon_type_scope(); + let (bare_fn_ty, _) = + self.ty_of_method_or_bare_fn(bf.unsafety, + bf.abi, + None, + &bf.decl, + anon_scope, + anon_scope); // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not wellformed. @@ -1751,10 +1763,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Create the anonymized type. let def_id = tcx.map.local_def_id(ast_ty.id); - let substs = tcx.mk_substs(Substs::empty()); + let substs = if let Some(anon_scope) = rscope.anon_type_scope() { + anon_scope.fresh_substs(tcx) + } else { + span_err!(tcx.sess, ast_ty.span, E0562, + "`impl Trait` not allowed outside of function \ + and inherent method return types"); + tcx.mk_substs(Substs::empty()) + }; let ty = tcx.mk_anon(tcx.map.local_def_id(ast_ty.id), substs); - // Collect the bounds, i.e. the `Trait` in `impl Trait`. + // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`. let bounds = compute_bounds(self, ty, bounds, SizedByDefault::Yes, ast_ty.span); let predicates = tcx.lift_to_global(&bounds.predicates(tcx, ty)).unwrap(); let predicates = ty::GenericPredicates { @@ -1828,36 +1847,40 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn ty_of_method(&self, sig: &hir::MethodSig, - untransformed_self_ty: Ty<'tcx>) + untransformed_self_ty: Ty<'tcx>, + anon_scope: Option) -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) { - let (bare_fn_ty, optional_explicit_self_category) = - self.ty_of_method_or_bare_fn(sig.unsafety, - sig.abi, - Some(untransformed_self_ty), - &sig.decl); - (bare_fn_ty, optional_explicit_self_category) + self.ty_of_method_or_bare_fn(sig.unsafety, + sig.abi, + Some(untransformed_self_ty), + &sig.decl, + None, + anon_scope) } pub fn ty_of_bare_fn(&self, unsafety: hir::Unsafety, abi: abi::Abi, - decl: &hir::FnDecl) + decl: &hir::FnDecl, + anon_scope: Option) -> &'tcx ty::BareFnTy<'tcx> { - self.ty_of_method_or_bare_fn(unsafety, abi, None, decl).0 + self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope).0 } - fn ty_of_method_or_bare_fn<'a>(&self, - unsafety: hir::Unsafety, - abi: abi::Abi, - opt_untransformed_self_ty: Option>, - decl: &hir::FnDecl) - -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) + fn ty_of_method_or_bare_fn(&self, + unsafety: hir::Unsafety, + abi: abi::Abi, + opt_untransformed_self_ty: Option>, + decl: &hir::FnDecl, + arg_anon_scope: Option, + ret_anon_scope: Option) + -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) { debug!("ty_of_method_or_bare_fn"); // New region names that appear inside of the arguments of the function // declaration are bound to that function type. - let rb = rscope::BindingRscope::new(); + let rb = MaybeWithAnonTypes::new(BindingRscope::new(), arg_anon_scope); // `implied_output_region` is the region that will be assumed for any // region parameters in the return type. In accordance with the rules for @@ -1895,7 +1918,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let output_ty = match decl.output { hir::Return(ref output) => ty::FnConverging(self.convert_ty_with_lifetime_elision(implied_output_region, - &output)), + &output, + ret_anon_scope)), hir::DefaultReturn(..) => ty::FnConverging(self.tcx().mk_nil()), hir::NoReturn(..) => ty::FnDiverging }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 480a166f56a..7c52ea5f3c9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -564,13 +564,17 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ty_generic_predicates = ty_generic_predicates_for_fn(ccx, &sig.generics, rcvr_ty_predicates); - let (fty, explicit_self_category) = + let (fty, explicit_self_category) = { + let anon_scope = match container { + ImplContainer(_) => Some(AnonTypeScope::new(&ty_generics)), + TraitContainer(_) => None + }; AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - sig, - untransformed_rcvr_ty); + sig, untransformed_rcvr_ty, anon_scope) + }; let def_id = ccx.tcx.map.local_def_id(id); - let substs = mk_item_substs(ccx, &ty_generics); + let substs = mk_item_substs(ccx.tcx, &ty_generics); let ty_method = ty::Method::new(name, ty_generics, @@ -961,7 +965,7 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, .map(|field| field.unsubst_ty()) .collect(); let def_id = tcx.map.local_def_id(ctor_id); - let substs = mk_item_substs(ccx, &scheme.generics); + let substs = mk_item_substs(tcx, &scheme.generics); tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: abi::Abi::Rust, @@ -1460,9 +1464,10 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } 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 tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl, + Some(AnonTypeScope::new(&ty_generics))); let def_id = ccx.tcx.map.local_def_id(it.id); - let substs = mk_item_substs(ccx, &ty_generics); + let substs = mk_item_substs(tcx, &ty_generics); let ty = tcx.mk_fn_def(def_id, substs, tofd); ty::TypeScheme { ty: ty, generics: ty_generics } } @@ -1474,14 +1479,14 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, 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 substs = mk_item_substs(tcx, &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 substs = mk_item_substs(tcx, &ty_generics); let t = tcx.mk_struct(def, substs); ty::TypeScheme { ty: t, generics: ty_generics } } @@ -2194,7 +2199,7 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( } } - let substs = mk_item_substs(ccx, &ty_generics); + let substs = mk_item_substs(ccx.tcx, &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, @@ -2209,19 +2214,19 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( } } -fn mk_item_substs<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - ty_generics: &ty::Generics<'tcx>) - -> &'tcx Substs<'tcx> +pub fn mk_item_substs<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + ty_generics: &ty::Generics) + -> &'tcx Substs<'tcx> { let types = ty_generics.types.map( - |def| ccx.tcx.mk_param_from_def(def)); + |def| 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)) + tcx.mk_substs(Substs::new(types, regions)) } /// Checks that all the type parameters on an impl diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 64b27857d2c..49c35d1b7ef 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4084,4 +4084,6 @@ register_diagnostics! { E0513, // no type for local variable .. E0521, // redundant default implementations of trait E0533, // `{}` does not name a unit variant, unit struct or a constant + E0562, // `impl Trait` not allowed outside of function + // and inherent method return types } diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 336a6170868..58d1ec9d02a 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -9,7 +9,8 @@ // except according to those terms. -use rustc::ty; +use rustc::ty::{self, TyCtxt}; +use rustc::ty::subst::Substs; use std::cell::Cell; use syntax_pos::Span; @@ -50,6 +51,79 @@ pub trait RegionScope { /// computing `object_lifetime_default` (in particular, in legacy /// modes, it may not be relevant). fn base_object_lifetime_default(&self, span: Span) -> ty::Region; + + /// If this scope allows anonymized types, return the generics in + /// scope, that anonymized types will close over. For example, + /// if you have a function like: + /// + /// fn foo<'a, T>() -> impl Trait { ... } + /// + /// then, for the rscope that is used when handling the return type, + /// `anon_type_scope()` would return a `Some(AnonTypeScope {...})`, + /// on which `.fresh_substs(...)` can be used to obtain identity + /// Substs for `'a` and `T`, to track them in `TyAnon`. This property + /// is controlled by the region scope because it's fine-grained enough + /// to allow restriction of anonymized types to the syntactical extent + /// of a function's return type. + fn anon_type_scope(&self) -> Option { + None + } +} + +#[derive(Copy, Clone)] +pub struct AnonTypeScope<'a> { + generics: &'a ty::Generics<'a> +} + +impl<'a, 'b, 'gcx, 'tcx> AnonTypeScope<'a> { + pub fn new(generics: &'a ty::Generics<'a>) -> AnonTypeScope<'a> { + AnonTypeScope { + generics: generics + } + } + + pub fn fresh_substs(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> { + use collect::mk_item_substs; + + mk_item_substs(tcx, self.generics) + } +} + +/// A scope wrapper which optionally allows anonymized types. +#[derive(Copy, Clone)] +pub struct MaybeWithAnonTypes<'a, R> { + base_scope: R, + anon_scope: Option> +} + +impl<'a, R: RegionScope> MaybeWithAnonTypes<'a, R> { + pub fn new(base_scope: R, anon_scope: Option>) -> Self { + MaybeWithAnonTypes { + base_scope: base_scope, + anon_scope: anon_scope + } + } +} + +impl<'a, R: RegionScope> RegionScope for MaybeWithAnonTypes<'a, R> { + fn object_lifetime_default(&self, span: Span) -> Option { + self.base_scope.object_lifetime_default(span) + } + + fn anon_regions(&self, + span: Span, + count: usize) + -> Result, Option>> { + self.base_scope.anon_regions(span, count) + } + + fn base_object_lifetime_default(&self, span: Span) -> ty::Region { + self.base_scope.base_object_lifetime_default(span) + } + + fn anon_type_scope(&self) -> Option { + self.anon_scope + } } // A scope in which all regions must be explicitly named. This is used @@ -221,6 +295,10 @@ impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { { self.base_scope.anon_regions(span, count) } + + fn anon_type_scope(&self) -> Option { + self.base_scope.anon_type_scope() + } } /// A scope which simply shifts the Debruijn index of other scopes @@ -262,4 +340,8 @@ impl<'r> RegionScope for ShiftedRscope<'r> { } } } + + fn anon_type_scope(&self) -> Option { + self.base_scope.anon_type_scope() + } }