Skip to content

Refactor argument-position impl Trait #46754

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,9 +602,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_lifetime, lifetimes);
}
TyImplTraitUniversal(_, ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
}
TyTypeof(expression) => {
visitor.visit_nested_body(expression)
}
Expand Down
83 changes: 64 additions & 19 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ use syntax::attr;
use syntax::ast::*;
use syntax::errors;
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::codemap::{self, respan, Spanned, CompilerDesugaringKind};
use syntax::std_inject;
Expand Down Expand Up @@ -106,6 +107,13 @@ pub struct LoweringContext<'a> {
is_in_loop_condition: bool,
is_in_trait_impl: bool,

// This is a list of in-band type definitions being generated by
// Argument-position `impl Trait`.
// When traversing a signature such as `fn foo(x: impl Trait)`,
// we record `impl Trait` as a new type parameter, then later
// add it on to `foo`s generics.
in_band_ty_params: Vec<hir::TyParam>,

// Used to create lifetime definitions from in-band lifetime usages.
// e.g. `fn foo(x: &'x u8) -> &'x u8` to `fn foo<'x>(x: &'x u8) -> &'x u8`
// When a named lifetime is encountered in a function or impl header and
Expand Down Expand Up @@ -197,6 +205,7 @@ pub fn lower_crate(sess: &Session,
node_id_to_hir_id: IndexVec::new(),
is_generator: false,
is_in_trait_impl: false,
in_band_ty_params: Vec::new(),
lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false,
in_scope_lifetimes: Vec::new(),
Expand Down Expand Up @@ -526,20 +535,23 @@ impl<'a> LoweringContext<'a> {
// Creates a new hir::LifetimeDef for every new lifetime encountered
// while evaluating `f`. Definitions are created with the parent provided.
// If no `parent_id` is provided, no definitions will be returned.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is out of date now I think, should talk also about type parameters

fn collect_in_band_lifetime_defs<T, F>(
fn collect_in_band_defs<T, F>(
&mut self,
parent_id: Option<DefId>,
f: F
) -> (Vec<hir::LifetimeDef>, T) where F: FnOnce(&mut LoweringContext) -> T
) -> (Vec<hir::TyParam>, Vec<hir::LifetimeDef>, T) where F: FnOnce(&mut LoweringContext) -> T
{
assert!(!self.is_collecting_in_band_lifetimes);
assert!(self.lifetimes_to_define.is_empty());
self.is_collecting_in_band_lifetimes = self.sess.features.borrow().in_band_lifetimes;

assert!(self.in_band_ty_params.is_empty());

let res = f(self);

self.is_collecting_in_band_lifetimes = false;

let in_band_ty_params = self.in_band_ty_params.split_off(0);
let lifetimes_to_define = self.lifetimes_to_define.split_off(0);

let lifetime_defs = match parent_id {
Expand Down Expand Up @@ -569,7 +581,7 @@ impl<'a> LoweringContext<'a> {
None => Vec::new(),
};

(lifetime_defs, res)
(in_band_ty_params, lifetime_defs, res)
}

// Evaluates `f` with the lifetimes in `lt_defs` in-scope.
Expand Down Expand Up @@ -613,29 +625,33 @@ impl<'a> LoweringContext<'a> {
res
}

// Appends in-band lifetime defs to the existing set of out-of-band lifetime defs.
// Evaluates all within the context of the out-of-band defs.
// If provided, `impl_item_id` is used to find the parent impls of impl items so
// that their generics are not duplicated.
fn add_in_band_lifetime_defs<F, T>(
// Appends in-band lifetime defs and argument-position `impl Trait` defs
// to the existing set of generics.
fn add_in_band_defs<F, T>(
&mut self,
generics: &Generics,
parent_id: Option<DefId>,
f: F
) -> (hir::Generics, T)
where F: FnOnce(&mut LoweringContext) -> T
{
let (in_band_defs, (mut lowered_generics, res)) =
let (in_band_ty_defs, in_band_lifetime_defs, (mut lowered_generics, res)) =
self.with_in_scope_lifetime_defs(&generics.lifetimes, |this| {
this.collect_in_band_lifetime_defs(parent_id, |this| {
this.collect_in_band_defs(parent_id, |this| {
(this.lower_generics(generics), f(this))
})
});

lowered_generics.ty_params =
lowered_generics.ty_params
.iter().cloned()
.chain(in_band_ty_defs.into_iter())
.collect();

lowered_generics.lifetimes =
lowered_generics.lifetimes
.iter().cloned()
.chain(in_band_defs.into_iter())
.chain(in_band_lifetime_defs.into_iter())
.collect();

(lowered_generics, res)
Expand Down Expand Up @@ -922,6 +938,7 @@ impl<'a> LoweringContext<'a> {
}
TyKind::ImplTrait(ref bounds) => {
use syntax::feature_gate::{emit_feature_err, GateIssue};
let span = t.span;
match itctx {
ImplTraitContext::Existential => {
let has_feature = self.sess.features.borrow().conservative_impl_trait;
Expand All @@ -944,7 +961,7 @@ impl<'a> LoweringContext<'a> {
id: self.next_id().node_id,
predicates: Vec::new().into(),
},
span: t.span,
span,
},
bounds: hir_bounds,
}, lifetimes)
Expand All @@ -956,7 +973,35 @@ impl<'a> LoweringContext<'a> {
t.span, GateIssue::Language,
"`impl Trait` in argument position is experimental");
}
hir::TyImplTraitUniversal(def_id, self.lower_bounds(bounds, itctx))

let def_node_id = self.next_id().node_id;

// Add a definition for the in-band TyParam
let def_index = self.resolver.definitions().create_def_with_parent(
def_id.index,
def_node_id,
DefPathData::ImplTrait,
DefIndexAddressSpace::High,
Mark::root()
);

let hir_bounds = self.lower_bounds(bounds, itctx);
self.in_band_ty_params.push(hir::TyParam {
// Set the name to `impl Bound1 + Bound2`
name: Symbol::intern(&pprust::ty_to_string(t)),
id: def_node_id,
bounds: hir_bounds,
default: None,
span,
pure_wrt_drop: false,
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
});

hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
span,
def: Def::TyParam(DefId::local(def_index)),
segments: vec![].into(),
})))
},
ImplTraitContext::Disallowed => {
span_err!(self.sess, t.span, E0562,
Expand Down Expand Up @@ -1829,7 +1874,7 @@ impl<'a> LoweringContext<'a> {
this.expr_block(body, ThinVec::new())
});
let (generics, fn_decl) =
this.add_in_band_lifetime_defs(generics, fn_def_id, |this|
this.add_in_band_defs(generics, fn_def_id, |this|
this.lower_fn_decl(decl, fn_def_id, true));

hir::ItemFn(fn_decl,
Expand Down Expand Up @@ -1883,7 +1928,7 @@ impl<'a> LoweringContext<'a> {
ref impl_items) => {
let def_id = self.resolver.definitions().opt_local_def_id(id);
let (generics, (ifce, lowered_ty)) =
self.add_in_band_lifetime_defs(ast_generics, def_id, |this| {
self.add_in_band_defs(ast_generics, def_id, |this| {
let ifce = ifce.as_ref().map(|trait_ref| {
this.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed)
});
Expand Down Expand Up @@ -2059,7 +2104,7 @@ impl<'a> LoweringContext<'a> {
}
TraitItemKind::Method(ref sig, None) => {
let names = this.lower_fn_args_to_names(&sig.decl);
this.add_in_band_lifetime_defs(&i.generics, fn_def_id, |this|
this.add_in_band_defs(&i.generics, fn_def_id, |this|
hir::TraitItemKind::Method(
this.lower_method_sig(sig, fn_def_id, false),
hir::TraitMethod::Required(names)))
Expand All @@ -2070,7 +2115,7 @@ impl<'a> LoweringContext<'a> {
this.expr_block(body, ThinVec::new())
});

this.add_in_band_lifetime_defs(&i.generics, fn_def_id, |this|
this.add_in_band_defs(&i.generics, fn_def_id, |this|
hir::TraitItemKind::Method(
this.lower_method_sig(sig, fn_def_id, false),
hir::TraitMethod::Provided(body_id)))
Expand Down Expand Up @@ -2147,7 +2192,7 @@ impl<'a> LoweringContext<'a> {
});
let impl_trait_return_allow = !this.is_in_trait_impl;

this.add_in_band_lifetime_defs(&i.generics, fn_def_id, |this|
this.add_in_band_defs(&i.generics, fn_def_id, |this|
hir::ImplItemKind::Method(
this.lower_method_sig(sig, fn_def_id, impl_trait_return_allow),
body_id))
Expand Down Expand Up @@ -2280,7 +2325,7 @@ impl<'a> LoweringContext<'a> {
ForeignItemKind::Fn(ref fdec, ref generics) => {
// Disallow impl Trait in foreign items
let (generics, (fn_dec, fn_args)) =
this.add_in_band_lifetime_defs(
this.add_in_band_defs(
generics,
Some(def_id),
|this| (
Expand Down
5 changes: 1 addition & 4 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1506,7 +1506,7 @@ pub enum Ty_ {
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
TyTraitObject(HirVec<PolyTraitRef>, Lifetime),
/// An exsitentially quantified (there exists a type satisfying) `impl
/// An existentially quantified (there exists a type satisfying) `impl
/// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
///
/// The `ExistTy` structure emulates an
Expand All @@ -1518,9 +1518,6 @@ pub enum Ty_ {
/// because all in-scope type parameters are captured by `impl Trait`,
/// so they are resolved directly through the parent `Generics`.
TyImplTraitExistential(ExistTy, HirVec<Lifetime>),
/// An universally quantified (for all types satisfying) `impl
/// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
TyImplTraitUniversal(DefId, TyParamBounds),
/// Unused for now
TyTypeof(BodyId),
/// TyInfer means the type should be inferred instead of it having been
Expand Down
3 changes: 0 additions & 3 deletions src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,6 @@ impl<'a> State<'a> {
hir::TyImplTraitExistential(ref existty, ref _lifetimes) => {
self.print_bounds("impl", &existty.bounds[..])?;
}
hir::TyImplTraitUniversal(_, ref bounds) => {
self.print_bounds("impl", &bounds[..])?;
}
hir::TyArray(ref ty, v) => {
self.s.word("[")?;
self.print_type(&ty)?;
Expand Down
1 change: 0 additions & 1 deletion src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,6 @@ impl_stable_hash_for!(enum hir::Ty_ {
TyPath(qpath),
TyTraitObject(trait_refs, lifetime),
TyImplTraitExistential(existty, lifetimes),
TyImplTraitUniversal(def_id, bounds),
TyTypeof(body_id),
TyErr,
TyInfer
Expand Down
13 changes: 0 additions & 13 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2146,19 +2146,6 @@ fn insert_late_bound_lifetimes(
visit_where_predicate,
&generics.where_clause.predicates
);
// We need to collect argument impl Trait lifetimes as well,
// we do so here.
walk_list!(
&mut appears_in_where_clause,
visit_ty,
decl.inputs
.iter()
.filter(|ty| if let hir::TyImplTraitUniversal(..) = ty.node {
true
} else {
false
})
);
for lifetime_def in &generics.lifetimes {
if !lifetime_def.bounds.is_empty() {
// `'a: 'b` means both `'a` and `'b` are referenced
Expand Down
8 changes: 0 additions & 8 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ use util::nodemap::FxHashSet;

use std::iter;
use syntax::{abi, ast};
use syntax::symbol::Symbol;
use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax_pos::Span;

Expand Down Expand Up @@ -1050,13 +1049,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
let def_id = tcx.hir.local_def_id(ast_ty.id);
self.impl_trait_ty_to_ty(def_id, lifetimes)
}
hir::TyImplTraitUniversal(fn_def_id, _) => {
let impl_trait_def_id = tcx.hir.local_def_id(ast_ty.id);
let generics = tcx.generics_of(fn_def_id);
let index = generics.type_param_to_index[&impl_trait_def_id.index];
tcx.mk_param(index,
Symbol::intern(&tcx.hir.node_to_pretty_string(ast_ty.id)))
}
hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
let opt_self_ty = maybe_qself.as_ref().map(|qself| {
Expand Down
Loading