Skip to content

Commit c91a899

Browse files
committed
Inherit generics for impl-trait.
1 parent 388b9d2 commit c91a899

File tree

10 files changed

+119
-454
lines changed

10 files changed

+119
-454
lines changed

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 32 additions & 224 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
6161
use rustc_hir::definitions::DefPathData;
6262
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
6363
use rustc_index::vec::{Idx, IndexVec};
64+
use rustc_middle::span_bug;
6465
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
65-
use rustc_middle::{bug, span_bug};
6666
use rustc_session::parse::feature_err;
6767
use rustc_span::hygiene::MacroKind;
6868
use rustc_span::source_map::DesugaringKind;
@@ -512,11 +512,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
512512
self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id)
513513
}
514514

515-
fn orig_local_def_id(&self, node: NodeId) -> LocalDefId {
516-
self.orig_opt_local_def_id(node)
517-
.unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
518-
}
519-
520515
/// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
521516
/// resolver (if any), after applying any remapping from `get_remapped_def_id`.
522517
///
@@ -1457,17 +1452,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
14571452
// frequently opened issues show.
14581453
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
14591454

1460-
let opaque_ty_def_id = match origin {
1461-
hir::OpaqueTyOrigin::TyAlias => self.create_def(
1462-
self.current_hir_id_owner.def_id,
1463-
opaque_ty_node_id,
1464-
DefPathData::ImplTrait,
1465-
),
1466-
hir::OpaqueTyOrigin::FnReturn(fn_def_id) => {
1467-
self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait)
1468-
}
1469-
hir::OpaqueTyOrigin::AsyncFn(..) => bug!("unreachable"),
1470-
};
1455+
let opaque_ty_def_id = self.create_def(
1456+
self.current_hir_id_owner.def_id,
1457+
opaque_ty_node_id,
1458+
DefPathData::ImplTrait,
1459+
);
14711460
debug!(?opaque_ty_def_id);
14721461

14731462
// Contains the new lifetime definitions created for the TAIT (if any).
@@ -1831,221 +1820,40 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18311820
let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
18321821
let fn_def_id = self.local_def_id(fn_node_id);
18331822

1834-
// When we create the opaque type for this async fn, it is going to have
1835-
// to capture all the lifetimes involved in the signature (including in the
1836-
// return type). This is done by introducing lifetime parameters for:
1837-
//
1838-
// - all the explicitly declared lifetimes from the impl and function itself;
1839-
// - all the elided lifetimes in the fn arguments;
1840-
// - all the elided lifetimes in the return type.
1841-
//
1842-
// So for example in this snippet:
1843-
//
1844-
// ```rust
1845-
// impl<'a> Foo<'a> {
1846-
// async fn bar<'b>(&self, x: &'b Vec<f64>, y: &str) -> &u32 {
1847-
// // ^ '0 ^ '1 ^ '2
1848-
// // elided lifetimes used below
1849-
// }
1850-
// }
1851-
// ```
1852-
//
1853-
// we would create an opaque type like:
1854-
//
1855-
// ```
1856-
// type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>;
1857-
// ```
1858-
//
1859-
// and we would then desugar `bar` to the equivalent of:
1860-
//
1861-
// ```rust
1862-
// impl<'a> Foo<'a> {
1863-
// fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_>
1864-
// }
1865-
// ```
1866-
//
1867-
// Note that the final parameter to `Bar` is `'_`, not `'2` --
1868-
// this is because the elided lifetimes from the return type
1869-
// should be figured out using the ordinary elision rules, and
1870-
// this desugaring achieves that.
1871-
1872-
// Calculate all the lifetimes that should be captured
1873-
// by the opaque type. This should include all in-scope
1874-
// lifetime parameters, including those defined in-band.
1875-
1876-
// Contains the new lifetime definitions created for the TAIT (if any) generated for the
1877-
// return type.
1878-
let mut collected_lifetimes = Vec::new();
1879-
let mut new_remapping = FxHashMap::default();
1880-
1881-
let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
1882-
debug!(?extra_lifetime_params);
1883-
for (ident, outer_node_id, outer_res) in extra_lifetime_params {
1884-
let outer_def_id = self.orig_local_def_id(outer_node_id);
1885-
let inner_node_id = self.next_node_id();
1886-
1887-
// Add a definition for the in scope lifetime def.
1888-
let inner_def_id = self.create_def(
1889-
opaque_ty_def_id,
1890-
inner_node_id,
1891-
DefPathData::LifetimeNs(ident.name),
1892-
);
1893-
new_remapping.insert(outer_def_id, inner_def_id);
1894-
1895-
let inner_res = match outer_res {
1896-
// Input lifetime like `'a`:
1897-
LifetimeRes::Param { param, .. } => {
1898-
LifetimeRes::Param { param, binder: fn_node_id }
1899-
}
1900-
// Input lifetime like `'1`:
1901-
LifetimeRes::Fresh { param, .. } => {
1902-
LifetimeRes::Fresh { param, binder: fn_node_id }
1903-
}
1904-
LifetimeRes::Static | LifetimeRes::Error => continue,
1905-
res => {
1906-
panic!(
1907-
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
1908-
res, ident, ident.span
1909-
)
1910-
}
1911-
};
1912-
1913-
let lifetime = Lifetime { id: outer_node_id, ident };
1914-
collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
1915-
}
1916-
1917-
debug!(?collected_lifetimes);
1918-
1919-
// We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
1920-
// find out exactly which ones those are.
1921-
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
1922-
// we only keep the lifetimes that appear in the `impl Debug` itself:
1923-
let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
1924-
debug!(?lifetimes_to_remap);
1925-
19261823
self.with_hir_id_owner(opaque_ty_node_id, |this| {
1927-
// If this opaque type is only capturing a subset of the lifetimes (those that appear
1928-
// in bounds), then create the new lifetime parameters required and create a mapping
1929-
// from the old `'a` (on the function) to the new `'a` (on the opaque type).
1930-
collected_lifetimes.extend(
1931-
this.create_lifetime_defs(
1932-
opaque_ty_def_id,
1933-
&lifetimes_to_remap,
1934-
&mut new_remapping,
1935-
)
1936-
.into_iter()
1937-
.map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
1824+
let future_bound = this.lower_async_fn_output_type_to_future_bound(
1825+
output,
1826+
span,
1827+
if in_trait && !this.tcx.features().return_position_impl_trait_in_trait {
1828+
ImplTraitContext::Disallowed(ImplTraitPosition::TraitReturn)
1829+
} else {
1830+
ImplTraitContext::ReturnPositionOpaqueTy {
1831+
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
1832+
in_trait,
1833+
}
1834+
},
19381835
);
1939-
debug!(?collected_lifetimes);
1940-
debug!(?new_remapping);
1941-
1942-
// Install the remapping from old to new (if any):
1943-
this.with_remapping(new_remapping, |this| {
1944-
// We have to be careful to get elision right here. The
1945-
// idea is that we create a lifetime parameter for each
1946-
// lifetime in the return type. So, given a return type
1947-
// like `async fn foo(..) -> &[&u32]`, we lower to `impl
1948-
// Future<Output = &'1 [ &'2 u32 ]>`.
1949-
//
1950-
// Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
1951-
// hence the elision takes place at the fn site.
1952-
let future_bound = this.lower_async_fn_output_type_to_future_bound(
1953-
output,
1954-
span,
1955-
if in_trait && !this.tcx.features().return_position_impl_trait_in_trait {
1956-
ImplTraitContext::Disallowed(ImplTraitPosition::TraitReturn)
1957-
} else {
1958-
ImplTraitContext::ReturnPositionOpaqueTy {
1959-
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
1960-
in_trait,
1961-
}
1962-
},
1963-
);
1964-
1965-
let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
1966-
|&(new_node_id, lifetime, _)| {
1967-
let hir_id = this.lower_node_id(new_node_id);
1968-
debug_assert_ne!(this.opt_local_def_id(new_node_id), None);
1969-
1970-
let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
1971-
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
1972-
} else {
1973-
(
1974-
hir::ParamName::Plain(lifetime.ident),
1975-
hir::LifetimeParamKind::Explicit,
1976-
)
1977-
};
1978-
1979-
hir::GenericParam {
1980-
hir_id,
1981-
name,
1982-
span: lifetime.ident.span,
1983-
pure_wrt_drop: false,
1984-
kind: hir::GenericParamKind::Lifetime { kind },
1985-
colon_span: None,
1986-
}
1987-
},
1988-
));
1989-
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
19901836

1991-
let opaque_ty_item = hir::OpaqueTy {
1992-
generics: this.arena.alloc(hir::Generics {
1993-
params: generic_params,
1994-
predicates: &[],
1995-
has_where_clause_predicates: false,
1996-
where_clause_span: this.lower_span(span),
1997-
span: this.lower_span(span),
1998-
}),
1999-
bounds: arena_vec![this; future_bound],
2000-
origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
2001-
in_trait,
2002-
};
1837+
let opaque_ty_item = hir::OpaqueTy {
1838+
generics: this.arena.alloc(hir::Generics {
1839+
params: &[],
1840+
predicates: &[],
1841+
has_where_clause_predicates: false,
1842+
where_clause_span: this.lower_span(span),
1843+
span: this.lower_span(span),
1844+
}),
1845+
bounds: arena_vec![this; future_bound],
1846+
origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
1847+
in_trait,
1848+
};
20031849

2004-
trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
2005-
this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
2006-
})
1850+
trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
1851+
this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
20071852
});
20081853

2009-
// As documented above, we need to create the lifetime
2010-
// arguments to our opaque type. Continuing with our example,
2011-
// we're creating the type arguments for the return type:
2012-
//
2013-
// ```
2014-
// Bar<'a, 'b, '0, '1, '_>
2015-
// ```
2016-
//
2017-
// For the "input" lifetime parameters, we wish to create
2018-
// references to the parameters themselves, including the
2019-
// "implicit" ones created from parameter types (`'a`, `'b`,
2020-
// '`0`, `'1`).
2021-
//
2022-
// For the "output" lifetime parameters, we just want to
2023-
// generate `'_`.
2024-
let generic_args = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
2025-
|(_, lifetime, res)| {
2026-
let id = self.next_node_id();
2027-
let span = lifetime.ident.span;
2028-
2029-
let ident = if lifetime.ident.name == kw::UnderscoreLifetime {
2030-
Ident::with_dummy_span(kw::UnderscoreLifetime)
2031-
} else {
2032-
lifetime.ident
2033-
};
2034-
2035-
let res = res.unwrap_or(
2036-
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
2037-
);
2038-
hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, span, ident, res))
2039-
},
2040-
));
2041-
2042-
// Create the `Foo<...>` reference itself. Note that the `type
2043-
// Foo = impl Trait` is, internally, created as a child of the
2044-
// async fn, so the *type parameters* are inherited. It's
2045-
// only the lifetime parameters that we must supply.
20461854
let opaque_ty_ref = hir::TyKind::OpaqueDef(
20471855
hir::ItemId { def_id: hir::OwnerId { def_id: opaque_ty_def_id } },
2048-
generic_args,
1856+
&[],
20491857
in_trait,
20501858
);
20511859
let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);

compiler/rustc_ast_lowering/src/lifetime_collector.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::ResolverAstLoweringExt;
22
use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
3-
use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
3+
use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
44
use rustc_hir::def::LifetimeRes;
55
use rustc_middle::span_bug;
66
use rustc_middle::ty::ResolverAstLowering;
@@ -21,7 +21,9 @@ impl<'ast> LifetimeCollectVisitor<'ast> {
2121
fn record_lifetime_use(&mut self, lifetime: Lifetime) {
2222
match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) {
2323
LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => {
24-
if !self.current_binders.contains(&binder) {
24+
if !self.current_binders.contains(&binder)
25+
&& !self.resolver.node_id_to_def_id.contains_key(&binder)
26+
{
2527
if !self.collected_lifetimes.contains(&lifetime) {
2628
self.collected_lifetimes.push(lifetime);
2729
}
@@ -94,12 +96,6 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
9496
}
9597
}
9698

97-
pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> {
98-
let mut visitor = LifetimeCollectVisitor::new(resolver);
99-
visitor.visit_fn_ret_ty(ret_ty);
100-
visitor.collected_lifetimes
101-
}
102-
10399
pub fn lifetimes_in_bounds(
104100
resolver: &ResolverAstLowering,
105101
bounds: &GenericBounds,

compiler/rustc_hir_analysis/src/astconv/mod.rs

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2720,35 +2720,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
27202720
let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
27212721
if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
27222722
// Our own parameters are the resolved lifetimes.
2723-
if let GenericParamDefKind::Lifetime { .. } = param.kind {
2724-
if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] {
2725-
self.ast_region_to_region(lifetime, None).into()
2726-
} else {
2727-
bug!()
2728-
}
2729-
} else {
2730-
bug!()
2731-
}
2723+
let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() };
2724+
let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() };
2725+
self.ast_region_to_region(lifetime, None).into()
27322726
} else {
2733-
match param.kind {
2734-
// For RPIT (return position impl trait), only lifetimes
2735-
// mentioned in the impl Trait predicate are captured by
2736-
// the opaque type, so the lifetime parameters from the
2737-
// parent item need to be replaced with `'static`.
2738-
//
2739-
// For `impl Trait` in the types of statics, constants,
2740-
// locals and type aliases. These capture all parent
2741-
// lifetimes, so they can use their identity subst.
2742-
GenericParamDefKind::Lifetime { .. }
2743-
if matches!(
2744-
origin,
2745-
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..)
2746-
) =>
2747-
{
2748-
tcx.lifetimes.re_static.into()
2749-
}
2750-
_ => tcx.mk_param_from_def(param),
2751-
}
2727+
tcx.mk_param_from_def(param)
27522728
}
27532729
});
27542730
debug!("impl_trait_ty_to_ty: substs={:?}", substs);
@@ -2922,6 +2898,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
29222898
Some(ty)
29232899
}
29242900

2901+
#[instrument(level = "trace", skip(self, generate_err))]
29252902
fn validate_late_bound_regions(
29262903
&self,
29272904
constrained_regions: FxHashSet<ty::BoundRegionKind>,

0 commit comments

Comments
 (0)