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={:?}",
//
// 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,
// 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.
struct AllCollector {
regions: FnvHashSet<ast::Name>,
+ 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);
+ }
}
}
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};
fn convert_ty_with_lifetime_elision(&self,
elided_lifetime: ElidedLifetime,
- ty: &hir::Ty)
+ ty: &hir::Ty,
+ anon_scope: Option<AnonTypeScope>)
-> 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)
}
}
}
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,
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 => {
}
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.
// 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 {
pub fn ty_of_method(&self,
sig: &hir::MethodSig,
- untransformed_self_ty: Ty<'tcx>)
+ untransformed_self_ty: Ty<'tcx>,
+ anon_scope: Option<AnonTypeScope>)
-> (&'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<AnonTypeScope>)
-> &'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<Ty<'tcx>>,
- 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<Ty<'tcx>>,
+ decl: &hir::FnDecl,
+ arg_anon_scope: Option<AnonTypeScope>,
+ ret_anon_scope: Option<AnonTypeScope>)
+ -> (&'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
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
};
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,
.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,
}
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 }
}
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 }
}
}
}
- 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,
}
}
-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
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
}
// 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;
/// 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<AnonTypeScope> {
+ 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<AnonTypeScope<'a>>
+}
+
+impl<'a, R: RegionScope> MaybeWithAnonTypes<'a, R> {
+ pub fn new(base_scope: R, anon_scope: Option<AnonTypeScope<'a>>) -> 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<ty::Region> {
+ self.base_scope.object_lifetime_default(span)
+ }
+
+ fn anon_regions(&self,
+ span: Span,
+ count: usize)
+ -> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
+ 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<AnonTypeScope> {
+ self.anon_scope
+ }
}
// A scope in which all regions must be explicitly named. This is used
{
self.base_scope.anon_regions(span, count)
}
+
+ fn anon_type_scope(&self) -> Option<AnonTypeScope> {
+ self.base_scope.anon_type_scope()
+ }
}
/// A scope which simply shifts the Debruijn index of other scopes
}
}
}
+
+ fn anon_type_scope(&self) -> Option<AnonTypeScope> {
+ self.base_scope.anon_type_scope()
+ }
}