Rollup merge of #79298 - lcnr:new-elysium, r=matthewjasper

correctly deal with late-bound lifetimes in anon consts

adds support for using late bound lifetimes of the parent context in anon consts.
```rust
#![feature(const_generics)]
const fn inner<'a>() -> usize where &'a (): Sized { 3 }

fn test<'a>() {
    let _: [u8; inner::<'a>()];
}
```
The lifetime `'a` is late bound in `test` so it's not included in its generics but is instead dealt with separately in borrowck.
This didn't previously work for anon consts as they have to use the late bound lifetimes of their parent which has
to be explicitly handled.

r? ```@matthewjasper``` cc ```@varkor``` ```@eddyb```
This commit is contained in:
Mara Bos 2021-01-17 12:24:39 +00:00 committed by GitHub
commit f783871ab1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 71 additions and 8 deletions

View File

@ -1316,7 +1316,7 @@ rustc_queries! {
desc { "looking up a named region" }
}
query is_late_bound_map(_: LocalDefId) ->
Option<&'tcx FxHashSet<ItemLocalId>> {
Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
desc { "testing if a region is late bound" }
}
query object_lifetime_defaults_map(_: LocalDefId)

View File

@ -2578,7 +2578,8 @@ impl<'tcx> TyCtxt<'tcx> {
}
pub fn is_late_bound(self, id: HirId) -> bool {
self.is_late_bound_map(id.owner).map_or(false, |set| set.contains(&id.local_id))
self.is_late_bound_map(id.owner)
.map_or(false, |(owner, set)| owner == id.owner && set.contains(&id.local_id))
}
pub fn object_lifetime_defaults(self, id: HirId) -> Option<&'tcx [ObjectLifetimeDefault]> {

View File

@ -788,13 +788,13 @@ fn for_each_late_bound_region_defined_on<'tcx>(
fn_def_id: DefId,
mut f: impl FnMut(ty::Region<'tcx>),
) {
if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
for late_bound in late_bounds.iter() {
let hir_id = HirId { owner: fn_def_id.expect_local(), local_id: *late_bound };
if let Some((owner, late_bounds)) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
for &late_bound in late_bounds.iter() {
let hir_id = HirId { owner, local_id: late_bound };
let name = tcx.hir().name(hir_id);
let region_def_id = tcx.hir().local_def_id(hir_id);
let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: fn_def_id,
scope: owner.to_def_id(),
bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name),
}));
f(liberated_region);

View File

@ -11,7 +11,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
use rustc_hir::def_id::{CrateNum, DefIdMap, LOCAL_CRATE};
use rustc_hir::hir_id::ItemLocalId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath};
use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind};
@ -20,6 +21,7 @@ use rustc_middle::middle::resolve_lifetime::*;
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use std::borrow::Cow;
@ -284,7 +286,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
resolve_lifetimes,
named_region_map: |tcx, id| tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id),
is_late_bound_map: |tcx, id| tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&id),
is_late_bound_map,
object_lifetime_defaults_map: |tcx, id| {
tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id)
},
@ -320,6 +322,32 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> ResolveLifetimes {
rl
}
fn is_late_bound_map<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
match tcx.def_kind(def_id) {
DefKind::AnonConst => {
let mut def_id = tcx
.parent(def_id.to_def_id())
.unwrap_or_else(|| bug!("anon const or closure without a parent"));
// We search for the next outer anon const or fn here
// while skipping closures.
//
// Note that for `AnonConst` we still just recurse until we
// find a function body, but who cares :shrug:
while tcx.is_closure(def_id) {
def_id = tcx
.parent(def_id)
.unwrap_or_else(|| bug!("anon const or closure without a parent"));
}
tcx.is_late_bound_map(def_id.expect_local())
}
_ => tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&def_id).map(|lt| (def_id, lt)),
}
}
fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap {
let krate = tcx.hir().krate();
let mut map = NamedRegionMap {

View File

@ -0,0 +1,18 @@
// run-pass
#![feature(const_generics)]
#![allow(incomplete_features)]
const fn inner<'a>() -> usize where &'a (): Sized {
3
}
fn test<'a>() {
let _ = || {
let _: [u8; inner::<'a>()];
let _ = [0; inner::<'a>()];
};
}
fn main() {
test();
}

View File

@ -0,0 +1,16 @@
// run-pass
#![feature(const_generics)]
#![allow(incomplete_features)]
const fn inner<'a>() -> usize where &'a (): Sized {
3
}
fn test<'a>() {
let _: [u8; inner::<'a>()];
let _ = [0; inner::<'a>()];
}
fn main() {
test();
}