rustc_typeck: move impl Trait checks out of RegionScope.
This commit is contained in:
parent
ba1849daec
commit
9783947c2a
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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)]
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user