diff options
| author | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-01-13 15:10:37 +0200 |
|---|---|---|
| committer | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2017-01-28 02:56:46 +0200 |
| commit | 9783947c2adfcadba3c0e036548cf6fd3e12553a (patch) | |
| tree | 1f63beb28b7bc1b10a11ea0f8ad671e1343dbb1e | |
| parent | ba1849daecf0ae8fee54cc32f378809a9531e5ed (diff) | |
| download | rust-9783947c2adfcadba3c0e036548cf6fd3e12553a.tar.gz rust-9783947c2adfcadba3c0e036548cf6fd3e12553a.zip | |
rustc_typeck: move impl Trait checks out of RegionScope.
| -rw-r--r-- | src/librustc_typeck/astconv.rs | 94 | ||||
| -rw-r--r-- | src/librustc_typeck/collect.rs | 32 | ||||
| -rw-r--r-- | src/librustc_typeck/lib.rs | 1 | ||||
| -rw-r--r-- | src/librustc_typeck/rscope.rs | 79 | ||||
| -rw-r--r-- | src/test/compile-fail/impl-trait/disallowed.rs | 2 |
5 files changed, 65 insertions, 143 deletions
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 42a220e1b9b..90efe7cad39 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -62,7 +62,7 @@ use rustc::ty::wf::object_region_bounds; use rustc_back::slice; use require_c_abi_if_variadic; use rscope::{RegionScope, ObjectLifetimeDefaultRscope, ShiftedRscope}; -use rscope::{AnonTypeScope, MaybeWithAnonTypes, ExplicitRscope}; +use rscope::ExplicitRscope; use util::common::{ErrorReported, FN_OUTPUT_NAME}; use util::nodemap::{NodeMap, FxHashSet}; @@ -361,8 +361,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } hir::ParenthesizedParameters(ref data) => { assert_eq!(i, 0); - let (ty, assoc) = - self.convert_parenthesized_parameters(rscope, substs, data); + let (ty, assoc) = self.convert_parenthesized_parameters(substs, data); output_assoc_binding = Some(assoc); ty } @@ -416,7 +415,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { vec![output_assoc_binding.unwrap_or_else(|| { // This is an error condition, but we should // get the associated type binding anyway. - self.convert_parenthesized_parameters(rscope, substs, data).1 + self.convert_parenthesized_parameters(substs, data).1 })] } }; @@ -428,20 +427,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } fn convert_parenthesized_parameters(&self, - rscope: &RegionScope, region_substs: &[Kind<'tcx>], data: &hir::ParenthesizedParameterData) -> (Ty<'tcx>, ConvertedBinding<'tcx>) { - let anon_scope = rscope.anon_type_scope(); - let rscope = MaybeWithAnonTypes::new(ExplicitRscope, anon_scope); let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| { - self.ast_ty_arg_to_ty(&rscope, None, region_substs, a_t) + self.ast_ty_arg_to_ty(&ExplicitRscope, None, region_substs, a_t) })); let (output, output_span) = match data.output { Some(ref output_ty) => { - (self.ast_ty_to_ty(&rscope, output_ty), output_ty.span) + (self.ast_ty_to_ty(&ExplicitRscope, output_ty), output_ty.span) } None => { (self.tcx().mk_nil(), data.span) @@ -1309,12 +1305,7 @@ 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 anon_scope = rscope.anon_type_scope(); - let bare_fn_ty = self.ty_of_method_or_bare_fn(bf.unsafety, - bf.abi, - &bf.decl, - anon_scope, - anon_scope); + let bare_fn_ty = self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl); // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not wellformed. @@ -1361,16 +1352,54 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyImplTrait(ref bounds) => { use collect::{compute_bounds, SizedByDefault}; + // Figure out if we can allow an `impl Trait` here, by walking up + // to a `fn` or inherent `impl` method, going only through `Ty` + // or `TraitRef` nodes (as nothing else should be in types) and + // ensuring that we reach the `fn`/method signature's return type. + let mut node_id = ast_ty.id; + let fn_decl = loop { + let parent = tcx.hir.get_parent_node(node_id); + match tcx.hir.get(parent) { + hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(ref fn_decl, ..), .. + }) => break Some(fn_decl), + + hir::map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(ref sig, _), .. + }) => { + match tcx.hir.expect_item(tcx.hir.get_parent(parent)).node { + hir::ItemImpl(.., None, _, _) => { + break Some(&sig.decl) + } + _ => break None + } + } + + hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => {} + + _ => break None + } + node_id = parent; + }; + let allow = fn_decl.map_or(false, |fd| { + match fd.output { + hir::DefaultReturn(_) => false, + hir::Return(ref ty) => ty.id == node_id + } + }); + // Create the anonymized type. - let def_id = tcx.hir.local_def_id(ast_ty.id); - if let Some(anon_scope) = rscope.anon_type_scope() { - let substs = anon_scope.fresh_substs(self, ast_ty.span); + if allow { + let def_id = tcx.hir.local_def_id(ast_ty.id); + if let Err(ErrorReported) = self.get_generics(ast_ty.span, def_id) { + return tcx.types.err; + } + let substs = Substs::identity_for_item(tcx, def_id); let ty = tcx.mk_anon(tcx.hir.local_def_id(ast_ty.id), substs); // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`. let bounds = compute_bounds(self, ty, bounds, SizedByDefault::Yes, - Some(anon_scope), ast_ty.span); let predicates = bounds.predicates(tcx, ty); let predicates = tcx.lift_to_global(&predicates).unwrap(); @@ -1450,36 +1479,19 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn ty_of_fn(&self, unsafety: hir::Unsafety, abi: abi::Abi, - decl: &hir::FnDecl, - anon_scope: Option<AnonTypeScope>) + decl: &hir::FnDecl) -> &'tcx ty::BareFnTy<'tcx> { - self.ty_of_method_or_bare_fn(unsafety, abi, decl, None, anon_scope) - } - - fn ty_of_method_or_bare_fn(&self, - unsafety: hir::Unsafety, - abi: abi::Abi, - decl: &hir::FnDecl, - arg_anon_scope: Option<AnonTypeScope>, - ret_anon_scope: Option<AnonTypeScope>) - -> &'tcx ty::BareFnTy<'tcx> - { - 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 = MaybeWithAnonTypes::new(ExplicitRscope, arg_anon_scope); + debug!("ty_of_fn"); let input_tys: Vec<Ty> = - decl.inputs.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect(); + decl.inputs.iter().map(|a| self.ty_of_arg(&ExplicitRscope, a, None)).collect(); let output_ty = match decl.output { - hir::Return(ref output) => - self.ast_ty_to_ty(&MaybeWithAnonTypes::new(ExplicitRscope, ret_anon_scope), output), + hir::Return(ref output) => self.ast_ty_to_ty(&ExplicitRscope, output), hir::DefaultReturn(..) => self.tcx().mk_nil(), }; - debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty); + debug!("ty_of_fn: output_ty={:?}", output_ty); self.tcx().mk_bare_fn(ty::BareFnTy { unsafety: unsafety, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 70bd43751eb..1bfa4fc7b68 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -641,7 +641,6 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: AssociatedItemContainer, id: ast::NodeId, sig: &hir::MethodSig, rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) { @@ -651,12 +650,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ty_generic_predicates = ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false); - let anon_scope = match container { - ImplContainer(_) => Some(AnonTypeScope::new(def_id)), - TraitContainer(_) => None - }; let fty = AstConv::ty_of_fn(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - sig.unsafety, sig.abi, &sig.decl, anon_scope); + sig.unsafety, sig.abi, &sig.decl); let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), ccx.tcx.hir.span(id), def_id); @@ -874,8 +869,7 @@ fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) { } hir::TraitItemKind::Method(ref sig, _) => { - convert_method(ccx, TraitContainer(trait_def_id), - trait_item.id, sig, &trait_predicates); + convert_method(ccx, trait_item.id, sig, &trait_predicates); } } } @@ -915,7 +909,7 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) { } hir::ImplItemKind::Method(ref sig, _) => { - convert_method(ccx, ImplContainer(impl_def_id), impl_item.id, sig, &impl_predicates); + convert_method(ccx, impl_item.id, sig, &impl_predicates); } } } @@ -1186,7 +1180,6 @@ fn ensure_super_predicates_step(ccx: &CrateCtxt, self_param_ty, bounds, SizedByDefault::No, - None, item.span); let superbounds1 = superbounds1.predicates(tcx, self_param_ty); @@ -1323,7 +1316,6 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) assoc_ty, bounds, SizedByDefault::Yes, - None, trait_item.span); bounds.predicates(ccx.tcx, assoc_ty).into_iter() @@ -1537,8 +1529,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx.icx(&()).to_ty(&ExplicitRscope, &t) } ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { - let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl, - Some(AnonTypeScope::new(def_id))); + let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); ccx.tcx.mk_fn_def(def_id, substs, tofd) } @@ -1770,7 +1761,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, param_ty, ¶m.bounds, SizedByDefault::Yes, - None, param.span); predicates.extend(bounds.predicates(ccx.tcx, param_ty)); } @@ -1968,7 +1958,6 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, param_ty: ty::Ty<'tcx>, ast_bounds: &[hir::TyParamBound], sized_by_default: SizedByDefault, - anon_scope: Option<AnonTypeScope>, span: Span) -> Bounds<'tcx> { @@ -1979,9 +1968,8 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, let mut projection_bounds = vec![]; - let rscope = MaybeWithAnonTypes::new(ExplicitRscope, anon_scope); let mut trait_bounds: Vec<_> = trait_bounds.iter().map(|&bound| { - astconv.instantiate_poly_trait_ref(&rscope, + astconv.instantiate_poly_trait_ref(&ExplicitRscope, bound, param_ty, &mut projection_bounds) @@ -2048,7 +2036,7 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( abi: abi::Abi) -> Ty<'tcx> { - let fty = AstConv::ty_of_fn(&ccx.icx(ast_generics), hir::Unsafety::Unsafe, abi, decl, None); + let fty = AstConv::ty_of_fn(&ccx.icx(ast_generics), hir::Unsafety::Unsafe, abi, decl); // feature gate SIMD types in FFI, since I (huonw) am not sure the // ABIs are handled at all correctly. @@ -2077,10 +2065,10 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>( ccx.tcx.mk_fn_def(def_id, substs, fty) } -pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, - span: Span, - def_id: DefId) - -> &'tcx Substs<'tcx> { +fn mk_item_substs<'tcx>(astconv: &AstConv<'tcx, 'tcx>, + span: Span, + def_id: DefId) + -> &'tcx Substs<'tcx> { let tcx = astconv.tcx(); // FIXME(eddyb) Do this request from Substs::for_item in librustc. if let Err(ErrorReported) = astconv.get_generics(span, def_id) { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 0e7daa03404..90ce77cc5f4 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -77,6 +77,7 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] +#![feature(loop_break_value)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 3ac917c396c..d982c91e388 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -8,11 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::hir::def_id::DefId; use rustc::ty; -use rustc::ty::subst::Substs; - -use astconv::AstConv; use syntax_pos::Span; @@ -38,73 +34,6 @@ 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<AnonTypeScope> { - None - } -} - -#[derive(Copy, Clone)] -pub struct AnonTypeScope { - enclosing_item: DefId -} - -impl<'gcx: 'tcx, 'tcx> AnonTypeScope { - pub fn new(enclosing_item: DefId) -> AnonTypeScope { - AnonTypeScope { - enclosing_item: enclosing_item - } - } - - pub fn fresh_substs(&self, astconv: &AstConv<'gcx, 'tcx>, span: Span) - -> &'tcx Substs<'tcx> { - use collect::mk_item_substs; - - mk_item_substs(astconv, span, self.enclosing_item) - } -} - -/// A scope wrapper which optionally allows anonymized types. -#[derive(Copy, Clone)] -pub struct MaybeWithAnonTypes<R> { - base_scope: R, - anon_scope: Option<AnonTypeScope> -} - -impl<R: RegionScope> MaybeWithAnonTypes<R> { - pub fn new(base_scope: R, anon_scope: Option<AnonTypeScope>) -> Self { - MaybeWithAnonTypes { - base_scope: base_scope, - anon_scope: anon_scope - } - } -} - -impl<R: RegionScope> RegionScope for MaybeWithAnonTypes<R> { - fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> { - self.base_scope.object_lifetime_default(span) - } - - 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 @@ -158,10 +87,6 @@ impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { 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.base_scope.anon_type_scope() - } } /// A scope which simply shifts the Debruijn index of other scopes @@ -185,8 +110,4 @@ impl<'r> RegionScope for ShiftedRscope<'r> { fn base_object_lifetime_default(&self, span: Span) -> ty::Region { ty::fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1) } - - fn anon_type_scope(&self) -> Option<AnonTypeScope> { - self.base_scope.anon_type_scope() - } } diff --git a/src/test/compile-fail/impl-trait/disallowed.rs b/src/test/compile-fail/impl-trait/disallowed.rs index 09aba5d8c91..0467c49b031 100644 --- a/src/test/compile-fail/impl-trait/disallowed.rs +++ b/src/test/compile-fail/impl-trait/disallowed.rs @@ -26,9 +26,9 @@ trait LazyToString { //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types } -// Note that the following impl doesn't error, because the trait is invalid. impl LazyToString for String { fn lazy_to_string<'a>(&'a self) -> impl Fn() -> String { + //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types || self.clone() } } |
