From 383ddca0af5a9b644330746481e7c66a366d55ed Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 22 Nov 2020 13:57:11 +0100 Subject: [PATCH 01/10] correctly deal with late-bound lifetimes in anon consts --- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 4 ++- .../src/borrow_check/universal_regions.rs | 8 ++--- compiler/rustc_resolve/src/late/lifetimes.rs | 32 +++++++++++++++++-- .../late-bound-vars/in_closure.rs | 18 +++++++++++ .../const-generics/late-bound-vars/simple.rs | 16 ++++++++++ 6 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/const-generics/late-bound-vars/in_closure.rs create mode 100644 src/test/ui/const-generics/late-bound-vars/simple.rs diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b516810205fef..5ed9c29dd03ca 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1271,7 +1271,7 @@ rustc_queries! { desc { "looking up a named region" } } query is_late_bound_map(_: LocalDefId) -> - Option<&'tcx FxHashSet> { + Option<(LocalDefId, &'tcx FxHashSet)> { desc { "testing if a region is late bound" } } query object_lifetime_defaults_map(_: LocalDefId) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f078bbacfe96c..fbc443ec729b6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2617,7 +2617,9 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn is_late_bound(self, id: HirId) -> bool { - self.is_late_bound_map(id.owner).map(|set| set.contains(&id.local_id)).unwrap_or(false) + self.is_late_bound_map(id.owner) + .map(|(owner, set)| owner == id.owner && set.contains(&id.local_id)) + .unwrap_or(false) } pub fn object_lifetime_defaults(self, id: HirId) -> Option<&'tcx [ObjectLifetimeDefault]> { diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs index 7ad38a1f82cd4..b4d1f51782cc2 100644 --- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs +++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs @@ -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::BoundRegion::BrNamed(region_def_id.to_def_id(), name), })); f(liberated_region); diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 91edbebc05f3b..24c8d0eb25db8 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -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)> { + 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 { diff --git a/src/test/ui/const-generics/late-bound-vars/in_closure.rs b/src/test/ui/const-generics/late-bound-vars/in_closure.rs new file mode 100644 index 0000000000000..0aaeaffb4cb9d --- /dev/null +++ b/src/test/ui/const-generics/late-bound-vars/in_closure.rs @@ -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(); +} diff --git a/src/test/ui/const-generics/late-bound-vars/simple.rs b/src/test/ui/const-generics/late-bound-vars/simple.rs new file mode 100644 index 0000000000000..2c411a3bdc5f3 --- /dev/null +++ b/src/test/ui/const-generics/late-bound-vars/simple.rs @@ -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(); +} From 3e6b19b1a95210fa724db1a1e420c4eeb8e2e78c Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 22 Nov 2020 15:56:00 +0100 Subject: [PATCH 02/10] cleanup --- compiler/rustc_ast_lowering/src/lib.rs | 4 ++-- compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2e1b5a74a7b7e..a25d2c72fd766 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1948,8 +1948,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params); let generic_params = - this.arena.alloc_from_iter(lifetime_params.iter().map(|(span, hir_name)| { - this.lifetime_to_generic_param(*span, *hir_name, opaque_ty_def_id) + this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name)| { + this.lifetime_to_generic_param(span, hir_name, opaque_ty_def_id) })); let opaque_ty_item = hir::OpaqueTy { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index e1a2f593b8d9b..308eb6097adec 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1125,6 +1125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. + #[instrument(skip(self, span))] pub fn instantiate_value_path( &self, segments: &[hir::PathSegment<'_>], @@ -1133,11 +1134,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, hir_id: hir::HirId, ) -> (Ty<'tcx>, Res) { - debug!( - "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})", - segments, self_ty, res, hir_id, - ); - let tcx = self.tcx; let path_segs = match res { From 735e85cac18d8f83e94783df9036a3f42151cda0 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 22 Nov 2020 16:55:52 +0100 Subject: [PATCH 03/10] add generics to `hir::AnonConst` --- compiler/rustc_ast_lowering/src/lib.rs | 70 +++++++++++++-- compiler/rustc_hir/src/hir.rs | 28 +++--- compiler/rustc_hir/src/intravisit.rs | 4 +- compiler/rustc_hir_pretty/src/lib.rs | 6 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- .../rustc_middle/src/hir/map/collector.rs | 14 ++- compiler/rustc_middle/src/ty/consts.rs | 85 +++++++++++++++++-- compiler/rustc_passes/src/check_const.rs | 2 +- compiler/rustc_passes/src/dead.rs | 2 +- compiler/rustc_passes/src/hir_id_validator.rs | 4 + compiler/rustc_passes/src/loops.rs | 2 +- compiler/rustc_resolve/src/late/lifetimes.rs | 6 ++ compiler/rustc_typeck/src/check/expr.rs | 2 +- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 4 +- compiler/rustc_typeck/src/check/wfcheck.rs | 1 + compiler/rustc_typeck/src/collect.rs | 6 +- src/librustdoc/clean/mod.rs | 2 +- src/test/ui/const-generics/binders/simple.rs | 5 ++ 18 files changed, 197 insertions(+), 48 deletions(-) create mode 100644 src/test/ui/const-generics/binders/simple.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a25d2c72fd766..fcb60b98ec847 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -512,6 +512,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => visit::walk_ty(self, t), } } + + fn visit_anon_const(&mut self, ct: &'tcx AnonConst) { + self.lctx.allocate_hir_id_counter(ct.id); + self.with_hir_id_owner(Some(ct.id), |this| { + visit::walk_anon_const(this, ct); + }); + } } self.lower_node_id(CRATE_NODE_ID); @@ -1158,9 +1165,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { tokens: None, }; - let ct = self.with_new_scopes(|this| hir::AnonConst { - hir_id: this.lower_node_id(node_id), - body: this.lower_const_body(path_expr.span, Some(&path_expr)), + let ct = self.lower_anon_const(&AnonConst { + id: node_id, + value: ast::ptr::P(path_expr), }); return GenericArg::Const(ConstArg { value: ct, span: ty.span }); } @@ -1169,7 +1176,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericArg::Type(self.lower_ty_direct(&ty, itctx)) } ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg { - value: self.lower_anon_const(&ct), + value: self.lower_anon_const(ct), span: ct.value.span, }), } @@ -2320,10 +2327,57 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.expr_block(block, AttrVec::new()) } - fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst { - self.with_new_scopes(|this| hir::AnonConst { - hir_id: this.lower_node_id(c.id), - body: this.lower_const_body(c.value.span, Some(&c.value)), + fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst<'hir> { + self.with_new_scopes(|this| { + this.allocate_hir_id_counter(c.id); + this.with_hir_id_owner(c.id, |this| { + let def_id = this.resolver.local_def_id(c.id); + + let hir_id = this.lower_node_id(c.id); + // Calculate all the lifetimes that should be captured + // by the opaque type. This should include all in-scope + // lifetime parameters, including those defined in-band. + // + // Note: this must be done after lowering the output type, + // as the output type may introduce new in-band lifetimes. + let lifetime_params: Vec<(Span, ParamName)> = this + .in_scope_lifetimes + .iter() + .cloned() + .map(|name| (name.ident().span, name)) + .chain(this.lifetimes_to_define.iter().cloned()) + .collect(); + + let generic_params = + this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name)| { + this.lifetime_to_generic_param(span, hir_name, def_id) + })); + + let mut generic_args = Vec::with_capacity(lifetime_params.len()); + generic_args.extend(lifetime_params.iter().map(|&(span, hir_name)| { + GenericArg::Lifetime(hir::Lifetime { + hir_id: this.next_id(), + span, + name: hir::LifetimeName::Param(hir_name), + }) + })); + let generic_args = this.arena.alloc_from_iter(generic_args); + + hir::AnonConst { + hir_id, + generics: hir::Generics { + params: generic_params, + where_clause: hir::WhereClause { predicates: &[], span: c.value.span }, + span: c.value.span, + }, + generic_args: hir::GenericArgs { + args: generic_args, + bindings: &[], + parenthesized: false, + }, + body: this.lower_const_body(c.value.span, Some(&c.value)), + } + }) }) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f01d44171056f..c2bcf3f0654e4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -241,9 +241,9 @@ impl<'hir> PathSegment<'hir> { } } -#[derive(Encodable, Debug, HashStable_Generic)] -pub struct ConstArg { - pub value: AnonConst, +#[derive(Debug, HashStable_Generic)] +pub struct ConstArg<'hir> { + pub value: AnonConst<'hir>, pub span: Span, } @@ -251,7 +251,7 @@ pub struct ConstArg { pub enum GenericArg<'hir> { Lifetime(Lifetime), Type(Ty<'hir>), - Const(ConstArg), + Const(ConstArg<'hir>), } impl GenericArg<'_> { @@ -1354,9 +1354,11 @@ pub type Lit = Spanned; /// These are usually found nested inside types (e.g., array lengths) /// or expressions (e.g., repeat counts), and also used to define /// explicit discriminant values for enum variants. -#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)] -pub struct AnonConst { +#[derive(Debug, HashStable_Generic)] +pub struct AnonConst<'hir> { pub hir_id: HirId, + pub generics: Generics<'hir>, + pub generic_args: GenericArgs<'hir>, pub body: BodyId, } @@ -1371,7 +1373,7 @@ pub struct Expr<'hir> { // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -rustc_data_structures::static_assert_size!(Expr<'static>, 72); +rustc_data_structures::static_assert_size!(Expr<'static>, 144); impl Expr<'_> { pub fn precedence(&self) -> ExprPrecedence { @@ -1519,7 +1521,7 @@ pub enum ExprKind<'hir> { /// A `box x` expression. Box(&'hir Expr<'hir>), /// Allow anonymous constants from an inline `const` block - ConstBlock(AnonConst), + ConstBlock(AnonConst<'hir>), /// An array (e.g., `[a, b, c, d]`). Array(&'hir [Expr<'hir>]), /// A function call. @@ -1619,7 +1621,7 @@ pub enum ExprKind<'hir> { /// /// E.g., `[1; 5]`. The first expression is the element /// to be repeated; the second is the number of times to repeat it. - Repeat(&'hir Expr<'hir>, AnonConst), + Repeat(&'hir Expr<'hir>, AnonConst<'hir>), /// A suspension point for generators (i.e., `yield `). Yield(&'hir Expr<'hir>, YieldSource), @@ -2064,7 +2066,7 @@ pub enum TyKind<'hir> { /// A variable length slice (i.e., `[T]`). Slice(&'hir Ty<'hir>), /// A fixed length array (i.e., `[T; n]`). - Array(&'hir Ty<'hir>, AnonConst), + Array(&'hir Ty<'hir>, AnonConst<'hir>), /// A raw pointer (i.e., `*const T` or `*mut T`). Ptr(MutTy<'hir>), /// A reference (i.e., `&'a T` or `&'a mut T`). @@ -2090,7 +2092,7 @@ pub enum TyKind<'hir> { /// where `Bound` is a trait or a lifetime. TraitObject(&'hir [PolyTraitRef<'hir>], Lifetime), /// Unused for now. - Typeof(AnonConst), + Typeof(AnonConst<'hir>), /// `TyKind::Infer` means the type should be inferred instead of it having been /// specified. This can appear anywhere in a type. Infer, @@ -2306,7 +2308,7 @@ pub struct Variant<'hir> { /// Fields and constructor id of the variant. pub data: VariantData<'hir>, /// Explicit discriminant (e.g., `Foo = 1`). - pub disr_expr: Option, + pub disr_expr: Option>, /// Span pub span: Span, } @@ -2693,7 +2695,7 @@ pub enum Node<'hir> { ImplItem(&'hir ImplItem<'hir>), Variant(&'hir Variant<'hir>), Field(&'hir StructField<'hir>), - AnonConst(&'hir AnonConst), + AnonConst(&'hir AnonConst<'hir>), Expr(&'hir Expr<'hir>), Stmt(&'hir Stmt<'hir>), PathSegment(&'hir PathSegment<'hir>), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3e8fc689acf7a..fde9c05d94d31 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -362,7 +362,7 @@ pub trait Visitor<'v>: Sized { fn visit_pat(&mut self, p: &'v Pat<'v>) { walk_pat(self, p) } - fn visit_anon_const(&mut self, c: &'v AnonConst) { + fn visit_anon_const(&mut self, c: &'v AnonConst<'v>) { walk_anon_const(self, c) } fn visit_expr(&mut self, ex: &'v Expr<'v>) { @@ -1089,7 +1089,7 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { } } -pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) { +pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst<'v>) { visitor.visit_id(constant.hir_id); visitor.visit_nested_body(constant.body); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 25b09d76295f2..fd3689d8ae1e7 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1083,7 +1083,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Block(blk)) } - pub fn print_anon_const(&mut self, constant: &hir::AnonConst) { + pub fn print_anon_const(&mut self, constant: &hir::AnonConst<'_>) { self.ann.nested(self, Nested::Body(constant.body)) } @@ -1132,14 +1132,14 @@ impl<'a> State<'a> { self.end() } - fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst) { + fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst<'_>) { self.ibox(INDENT_UNIT); self.s.word_space("const"); self.print_anon_const(anon_const); self.end() } - fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) { + fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst<'_>) { self.ibox(INDENT_UNIT); self.s.word("["); self.print_expr(element); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 46dd0df65e06f..a94bf601a6d2e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1780,7 +1780,7 @@ impl Visitor<'tcx> for EncodeContext<'a, 'tcx> { intravisit::walk_expr(self, ex); self.encode_info_for_expr(ex); } - fn visit_anon_const(&mut self, c: &'tcx AnonConst) { + fn visit_anon_const(&mut self, c: &'tcx AnonConst<'_>) { intravisit::walk_anon_const(self, c); let def_id = self.tcx.hir().local_def_id(c.hir_id); self.encode_info_for_anon_const(def_id); diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 82cfca4f17101..4a8fecd590c2a 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -441,11 +441,17 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - fn visit_anon_const(&mut self, constant: &'hir AnonConst) { - self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant)); + fn visit_anon_const(&mut self, constant: &'hir AnonConst<'hir>) { + debug_assert_eq!( + constant.hir_id.owner, + self.definitions.opt_hir_id_to_local_def_id(constant.hir_id).unwrap() + ); + self.with_dep_node_owner(constant.hir_id.owner, constant, |this, hash| { + this.insert_with_hash(DUMMY_SP, constant.hir_id, Node::AnonConst(constant), hash); - self.with_parent(constant.hir_id, |this| { - intravisit::walk_anon_const(this, constant); + this.with_parent(constant.hir_id, |this| { + intravisit::walk_anon_const(this, constant); + }) }); } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 0af884a286d6e..f4042aeb44beb 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -3,6 +3,7 @@ use crate::mir::interpret::{LitToConstInput, Scalar}; use crate::ty::subst::InternalSubsts; use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{ParamEnv, ParamEnvAnd}; +use crate::middle::resolve_lifetime as rl; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -41,15 +42,17 @@ impl<'tcx> Const<'tcx> { let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - let body_id = match tcx.hir().get(hir_id) { - hir::Node::AnonConst(ac) => ac.body, + let hir_ct = match tcx.hir().get(hir_id) { + hir::Node::AnonConst(ac) => ac, _ => span_bug!( tcx.def_span(def.did.to_def_id()), "from_anon_const can only process anonymous constants" ), }; - let expr = &tcx.hir().body(body_id).value; + warn!(?hir_ct.generics, ?hir_ct.generic_args); + + let expr = &tcx.hir().body(hir_ct.body).value; let ty = tcx.type_of(def.def_id_for_type_of()); @@ -97,11 +100,77 @@ impl<'tcx> Const<'tcx> { let name = tcx.hir().name(hir_id); ty::ConstKind::Param(ty::ParamConst::new(index, name)) } - _ => ty::ConstKind::Unevaluated( - def.to_global(), - InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), - None, - ), + _ => { + let generics = tcx.generics_of(def.did); + let substs = InternalSubsts::for_item(tcx, def.did.to_def_id(), |param, _| { + if let Some(i) = + (param.index as usize).checked_sub(generics.parent_count) + { + // Our own parameters are the resolved lifetimes. + match param.kind { + ty::GenericParamDefKind::Lifetime => { + if let hir::GenericArg::Lifetime(lifetime) = &hir_ct.generic_args.args[i] { + let lifetime_name = |def_id| { + tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id)) + }; + + match tcx.named_region(lifetime.hir_id) { + Some(rl::Region::Static) => tcx.lifetimes.re_static, + + Some(rl::Region::LateBound(debruijn, id, _)) => { + let name = lifetime_name(id.expect_local()); + tcx.mk_region(ty::ReLateBound( + debruijn, + ty::BrNamed(id, name), + )) + } + + Some(rl::Region::LateBoundAnon(debruijn, index)) => tcx + .mk_region(ty::ReLateBound( + debruijn, + ty::BrAnon(index), + )), + + Some(rl::Region::EarlyBound(index, id, _)) => { + let name = lifetime_name(id.expect_local()); + tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { + def_id: id, + index, + name, + })) + } + + Some(rl::Region::Free(scope, id)) => { + let name = lifetime_name(id.expect_local()); + tcx.mk_region(ty::ReFree(ty::FreeRegion { + scope, + bound_region: ty::BrNamed(id, name), + })) + + // (*) -- not late-bound, won't change + } + + None => { + tcx.sess.delay_span_bug( + lifetime.span, + "unelided lifetime in signature", + ); + tcx.lifetimes.re_static + } + } + } else { + bug!() + } + }.into(), + _ => bug!(), + } + } else { + tcx.mk_param_from_def(param) + } + }); + + ty::ConstKind::Unevaluated(def.to_global(), substs, None) + } }; tcx.mk_const(ty::Const { val, ty }) diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index e37c6418eb81c..74270f8163ff6 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -183,7 +183,7 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { NestedVisitorMap::OnlyBodies(self.tcx.hir()) } - fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) { + fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst<'_>) { let kind = Some(hir::ConstContext::Const); self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index b87b13cff8053..291446dd48be0 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -320,7 +320,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { intravisit::walk_ty(self, ty); } - fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst<'_>) { self.live_symbols.insert(c.hir_id); intravisit::walk_anon_const(self, c); } diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index fdd6c23805564..abf1b48b30693 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -176,6 +176,10 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { // different owner. } + fn visit_anon_const(&mut self, _: &'hir hir::AnonConst<'hir>) { + // Do nothing here, the bodies of anon consts have a different hir owner. + } + fn visit_generic_param(&mut self, param: &'hir hir::GenericParam<'hir>) { if let hir::GenericParamKind::Type { synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 9b4da71e5e961..93d7dad8f8fe0 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -47,7 +47,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { NestedVisitorMap::OnlyBodies(self.hir_map) } - fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'hir hir::AnonConst<'_>) { self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c)); } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 24c8d0eb25db8..a82ea62c600c4 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -479,6 +479,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } + fn visit_anon_const(&mut self, ct: &'tcx hir::AnonConst<'tcx>) { + self.visit_generics(&ct.generics); + self.visit_generic_args(crate::DUMMY_SP, &ct.generic_args); + intravisit::walk_anon_const(self, ct); + } + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 26962d2222d32..9f080193916c5 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1022,7 +1022,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_expr_repeat( &self, element: &'tcx hir::Expr<'tcx>, - count: &'tcx hir::AnonConst, + count: &'tcx hir::AnonConst<'_>, expected: Expectation<'tcx>, _expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 308eb6097adec..8feda958a97dc 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -472,7 +472,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { + pub fn to_const(&self, ast_c: &hir::AnonConst<'_>) -> &'tcx ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); self.register_wf_obligation( @@ -485,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn const_arg_to_const( &self, - ast_c: &hir::AnonConst, + ast_c: &hir::AnonConst<'_>, param_def_id: DefId, ) -> &'tcx ty::Const<'tcx> { let const_def = ty::WithOptConstParam { diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index c09f8cce5b44d..9aece684a4e13 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1429,6 +1429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: self.non_enum_variant(&variant.data).fields, explicit_discr: variant .disr_expr + .as_ref() .map(|explicit_discr| self.tcx.hir().local_def_id(explicit_discr.hir_id)), }) .collect() diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index f8b7ccb2cd618..dbcf7449104c7 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1282,7 +1282,7 @@ impl<'v> Visitor<'v> for AnonConstInParamListDetector { self.in_param_list = prev; } - fn visit_anon_const(&mut self, c: &'v hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'v hir::AnonConst<'v>) { if self.in_param_list && self.ct == c.hir_id { self.found_anon_const_in_list = true; } else { @@ -1435,6 +1435,8 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { ForeignItemKind::Type => &no_generics, }, + Node::AnonConst(ct) => &ct.generics, + _ => &no_generics, }; @@ -2121,7 +2123,7 @@ fn const_evaluatable_predicates_of<'tcx>( intravisit::NestedVisitorMap::None } - fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst<'tcx>) { let def_id = self.tcx.hir().local_def_id(c.hir_id); let ct = ty::Const::from_anon_const(self.tcx, def_id); if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d294d8f02a80f..0b64de00e7187 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -430,7 +430,7 @@ impl Clean for hir::GenericParam<'_> { } } -impl Clean for hir::ConstArg { +impl Clean for hir::ConstArg<'_> { fn clean(&self, cx: &DocContext<'_>) -> Constant { Constant { type_: cx diff --git a/src/test/ui/const-generics/binders/simple.rs b/src/test/ui/const-generics/binders/simple.rs new file mode 100644 index 0000000000000..f558adc5fd4e4 --- /dev/null +++ b/src/test/ui/const-generics/binders/simple.rs @@ -0,0 +1,5 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] +struct Foo where [u8; { let _: &'a (); 3 }]: Sized; + +fn main() {} From b7c687c78154ac9d5bce34f2694641df3c47a5c3 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Mon, 23 Nov 2020 16:45:39 +0100 Subject: [PATCH 04/10] respite --- compiler/rustc_ast_lowering/src/lib.rs | 30 +++---- compiler/rustc_hir/src/intravisit.rs | 2 + compiler/rustc_middle/src/hir/map/mod.rs | 19 +++++ compiler/rustc_middle/src/query/mod.rs | 4 + compiler/rustc_middle/src/ty/consts.rs | 78 ++----------------- compiler/rustc_resolve/src/late/lifetimes.rs | 65 ++++++++++++++-- .../rustc_trait_selection/src/traits/wf.rs | 22 +++--- compiler/rustc_typeck/src/collect.rs | 3 +- compiler/rustc_typeck/src/collect/type_of.rs | 34 +++++++- .../ui/const-generics/binders/arr-in-arr.rs | 17 ++++ .../ui/const-generics/binders/const-eval.rs | 17 ++++ .../binders/generic_assoc_ty.rs | 19 +++++ src/test/ui/const-generics/binders/mixed.rs | 14 ++++ .../ui/const-generics/binders/multiple-lt.rs | 15 ++++ src/test/ui/const-generics/binders/simple.rs | 3 +- .../ui/const-generics/binders/trait-bound.rs | 25 ++++++ .../ui/const-generics/binders/unused-lt.rs | 16 ++++ 17 files changed, 279 insertions(+), 104 deletions(-) create mode 100644 src/test/ui/const-generics/binders/arr-in-arr.rs create mode 100644 src/test/ui/const-generics/binders/const-eval.rs create mode 100644 src/test/ui/const-generics/binders/generic_assoc_ty.rs create mode 100644 src/test/ui/const-generics/binders/mixed.rs create mode 100644 src/test/ui/const-generics/binders/multiple-lt.rs create mode 100644 src/test/ui/const-generics/binders/trait-bound.rs create mode 100644 src/test/ui/const-generics/binders/unused-lt.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index fcb60b98ec847..a119cb19f8189 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2335,11 +2335,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let hir_id = this.lower_node_id(c.id); // Calculate all the lifetimes that should be captured - // by the opaque type. This should include all in-scope - // lifetime parameters, including those defined in-band. + // by the anonymous constant. This is needed for binders, + // for example `for<'a> dyn Trait<{ inner_fn::<'a>() }> where + // we somehow have to deal with `'a` in the anonymous constant. // - // Note: this must be done after lowering the output type, - // as the output type may introduce new in-band lifetimes. + // We therefore add these lifetimes as additional generic parameters. + + // FIXME(const_generics): We currently add all lifetimes as generic params, + // but as we already mention the parent generics this is not actually needed. + // + // Consider only adding explicit higher ranked lifetimes here. let lifetime_params: Vec<(Span, ParamName)> = this .in_scope_lifetimes .iter() @@ -2353,15 +2358,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { this.lifetime_to_generic_param(span, hir_name, def_id) })); - let mut generic_args = Vec::with_capacity(lifetime_params.len()); - generic_args.extend(lifetime_params.iter().map(|&(span, hir_name)| { - GenericArg::Lifetime(hir::Lifetime { - hir_id: this.next_id(), - span, - name: hir::LifetimeName::Param(hir_name), - }) - })); - let generic_args = this.arena.alloc_from_iter(generic_args); + let generic_args = + this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name)| { + GenericArg::Lifetime(hir::Lifetime { + hir_id: this.next_id(), + span, + name: hir::LifetimeName::Param(hir_name), + }) + })); hir::AnonConst { hir_id, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index fde9c05d94d31..906845ea93c17 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1091,6 +1091,8 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst<'v>) { visitor.visit_id(constant.hir_id); + visitor.visit_generic_args(constant.generics.span, &constant.generic_args); + visitor.visit_generics(&constant.generics); visitor.visit_nested_body(constant.body); } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5e36362ec5916..6535698f8ec49 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -629,6 +629,25 @@ impl<'hir> Map<'hir> { None } + /// Returns the containing scope which may also define generics. + /// + /// Similar to `get_parent_item` except that it also + /// returns anonymous constants. + pub fn get_generic_context(&self, hir_id: HirId) -> HirId { + for (hir_id, node) in self.parent_iter(hir_id) { + match node { + Node::Crate(_) + | Node::Item(_) + | Node::ForeignItem(_) + | Node::TraitItem(_) + | Node::ImplItem(_) + | Node::AnonConst(_) => return hir_id, + _ => {} + } + } + hir_id + } + /// Retrieves the `HirId` for `id`'s parent item, or `id` itself if no /// parent item is in this map. The "parent item" is the closest parent node /// in the HIR which is recorded by the map and is an item, either an item diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5ed9c29dd03ca..8fae0e20f81fc 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -89,6 +89,10 @@ rustc_queries! { desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } } + query default_substs_for_anon_const(key: LocalDefId) -> SubstsRef<'tcx> { + desc { |tcx| "computing the identity substs for `{}`", tcx.def_path_str(key.to_def_id()) } + } + /// Computes the `DefId` of the corresponding const parameter in case the `key` is a /// const argument and returns `None` otherwise. /// diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index f4042aeb44beb..98760d4e91cc2 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,9 +1,7 @@ use crate::mir::interpret::ConstValue; use crate::mir::interpret::{LitToConstInput, Scalar}; -use crate::ty::subst::InternalSubsts; use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{ParamEnv, ParamEnvAnd}; -use crate::middle::resolve_lifetime as rl; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -100,77 +98,11 @@ impl<'tcx> Const<'tcx> { let name = tcx.hir().name(hir_id); ty::ConstKind::Param(ty::ParamConst::new(index, name)) } - _ => { - let generics = tcx.generics_of(def.did); - let substs = InternalSubsts::for_item(tcx, def.did.to_def_id(), |param, _| { - if let Some(i) = - (param.index as usize).checked_sub(generics.parent_count) - { - // Our own parameters are the resolved lifetimes. - match param.kind { - ty::GenericParamDefKind::Lifetime => { - if let hir::GenericArg::Lifetime(lifetime) = &hir_ct.generic_args.args[i] { - let lifetime_name = |def_id| { - tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id)) - }; - - match tcx.named_region(lifetime.hir_id) { - Some(rl::Region::Static) => tcx.lifetimes.re_static, - - Some(rl::Region::LateBound(debruijn, id, _)) => { - let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReLateBound( - debruijn, - ty::BrNamed(id, name), - )) - } - - Some(rl::Region::LateBoundAnon(debruijn, index)) => tcx - .mk_region(ty::ReLateBound( - debruijn, - ty::BrAnon(index), - )), - - Some(rl::Region::EarlyBound(index, id, _)) => { - let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { - def_id: id, - index, - name, - })) - } - - Some(rl::Region::Free(scope, id)) => { - let name = lifetime_name(id.expect_local()); - tcx.mk_region(ty::ReFree(ty::FreeRegion { - scope, - bound_region: ty::BrNamed(id, name), - })) - - // (*) -- not late-bound, won't change - } - - None => { - tcx.sess.delay_span_bug( - lifetime.span, - "unelided lifetime in signature", - ); - tcx.lifetimes.re_static - } - } - } else { - bug!() - } - }.into(), - _ => bug!(), - } - } else { - tcx.mk_param_from_def(param) - } - }); - - ty::ConstKind::Unevaluated(def.to_global(), substs, None) - } + _ => ty::ConstKind::Unevaluated( + def.to_global(), + tcx.default_substs_for_anon_const(def.did), + None, + ), }; tcx.mk_const(ty::Const { val, ty }) diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index a82ea62c600c4..31a993aef988e 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -28,7 +28,7 @@ use std::borrow::Cow; use std::cell::Cell; use std::mem::take; -use tracing::debug; +use tracing::*; // This counts the no of times a lifetime is used #[derive(Clone, Copy, Debug)] @@ -192,7 +192,7 @@ crate struct LifetimeContext<'a, 'tcx> { #[derive(Debug)] enum Scope<'a> { /// Declares lifetimes, and each can be early-bound or late-bound. - /// The `DebruijnIndex` of late-bound lifetimes starts at `1` and + /// The `DebruijnIndex` of late-bound lifetimes starts at `0` and /// it should be shifted by the number of `Binder`s in between the /// declaration `Binder` and the location it's referenced from. Binder { @@ -207,6 +207,12 @@ enum Scope<'a> { /// impls, but not other kinds of items. track_lifetime_uses: bool, + /// Whether these lifetimes are synthetic and only added + /// for anon consts. + /// + /// We do not emit lints in `check_uses_for_lifetimes_defined_by_scope`. + from_anon_const: bool, + /// Whether or not this binder would serve as the parent /// binder for opaque types introduced within. For example: /// @@ -467,6 +473,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { lifetimes, next_early_index: index + non_lifetime_count, opaque_type_parent: true, + from_anon_const: false, track_lifetime_uses, s: ROOT_SCOPE, }; @@ -480,9 +487,36 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_anon_const(&mut self, ct: &'tcx hir::AnonConst<'tcx>) { - self.visit_generics(&ct.generics); self.visit_generic_args(crate::DUMMY_SP, &ct.generic_args); - intravisit::walk_anon_const(self, ct); + + let generics = &ct.generics; + let mut index = self.next_early_index(); + debug!("visit_anon_const: index = {}", index); + let lifetimes = generics + .params + .iter() + .map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Region::early(&self.tcx.hir(), &mut index, param) + } + GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { + bug!("unexpected param: {:?}", param) + } + }) + .collect(); + let scope = Scope::Binder { + lifetimes, + next_early_index: index, + s: self.scope, + track_lifetime_uses: true, + from_anon_const: true, + opaque_type_parent: true, + }; + self.with(scope, |_, this| { + this.visit_id(ct.hir_id); + this.visit_generics(generics); + this.visit_nested_body(ct.body); + }); } fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { @@ -535,6 +569,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { s: self.scope, next_early_index, track_lifetime_uses: true, + from_anon_const: false, opaque_type_parent: false, }; self.with(scope, |old_scope, this| { @@ -708,6 +743,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { next_early_index, s: this.scope, track_lifetime_uses: true, + from_anon_const: false, opaque_type_parent: false, }; this.with(scope, |_old_scope, this| { @@ -723,6 +759,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { next_early_index, s: self.scope, track_lifetime_uses: true, + from_anon_const: false, opaque_type_parent: false, }; self.with(scope, |_old_scope, this| { @@ -775,6 +812,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { next_early_index: index + non_lifetime_count, s: self.scope, track_lifetime_uses: true, + from_anon_const: false, opaque_type_parent: true, }; self.with(scope, |old_scope, this| { @@ -837,6 +875,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { next_early_index: index + non_lifetime_count, s: self.scope, track_lifetime_uses: true, + from_anon_const: false, opaque_type_parent: true, }; self.with(scope, |old_scope, this| { @@ -934,6 +973,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { s: self.scope, next_early_index, track_lifetime_uses: true, + from_anon_const: false, opaque_type_parent: false, }; let result = self.with(scope, |old_scope, this| { @@ -977,6 +1017,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { s: self.scope, next_early_index: self.next_early_index(), track_lifetime_uses: true, + from_anon_const: false, opaque_type_parent: false, }; self.with(scope, |_, this| { @@ -1027,6 +1068,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { s: self.scope, next_early_index, track_lifetime_uses: true, + from_anon_const: false, opaque_type_parent: false, }; self.with(scope, |old_scope, this| { @@ -1370,6 +1412,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { f(self) } + #[instrument(skip(self, f))] fn with(&mut self, wrap_scope: Scope<'_>, f: F) where F: for<'b> FnOnce(ScopeRef<'_>, &mut LifetimeContext<'b, 'tcx>), @@ -1390,10 +1433,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { lifetime_uses, missing_named_lifetime_spots, }; - debug!("entering scope {:?}", this.scope); f(self.scope, &mut this); this.check_uses_for_lifetimes_defined_by_scope(); - debug!("exiting scope {:?}", this.scope); self.labels_in_fn = this.labels_in_fn; self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; self.missing_named_lifetime_spots = this.missing_named_lifetime_spots; @@ -1537,6 +1578,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn check_uses_for_lifetimes_defined_by_scope(&mut self) { let defined_by = match self.scope { + Scope::Binder { from_anon_const: true, .. } => { + debug!("check_uses_for_lifetimes_defined_by_scope: synthetic anon const binder"); + return; + } Scope::Binder { lifetimes, .. } => lifetimes, _ => { debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope"); @@ -1743,6 +1788,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { next_early_index, s: self.scope, opaque_type_parent: true, + from_anon_const: false, track_lifetime_uses: false, }; self.with(scope, move |old_scope, this| { @@ -2342,6 +2388,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.outer_index.shift_out(1); } + fn visit_anon_const(&mut self, _ct: &hir::AnonConst<'_>) { + // Do not look inside of anonymous constants, they should + // not participate in lifetime elision. + + // FIXME(const_generics): is this true? + } + fn visit_param_bound(&mut self, bound: &hir::GenericBound<'_>) { if let hir::GenericBound::LangItemTrait { .. } = bound { self.outer_index.shift_in(1); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 5bcb16d21e09c..c1b68c42000fd 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -434,15 +434,19 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let obligations = self.nominal_obligations(def.did, substs); self.out.extend(obligations); - let predicate = ty::PredicateAtom::ConstEvaluatable(def, substs) - .to_predicate(self.tcx()); - let cause = self.cause(traits::MiscObligation); - self.out.push(traits::Obligation::with_depth( - cause, - self.recursion_depth, - self.param_env, - predicate, - )); + // FIXME(const_generics): Do we actually end up having to deal with + // this bound later or is this unsound? + if !substs.has_escaping_bound_vars() { + let predicate = ty::PredicateAtom::ConstEvaluatable(def, substs) + .to_predicate(self.tcx()); + let cause = self.cause(traits::MiscObligation); + self.out.push(traits::Obligation::with_depth( + cause, + self.recursion_depth, + self.param_env, + predicate, + )); + } } ty::ConstKind::Infer(infer) => { let resolved = self.infcx.shallow_resolve(infer); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index dbcf7449104c7..0a2202eb4e744 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -70,6 +70,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { pub fn provide(providers: &mut Providers) { *providers = Providers { + default_substs_for_anon_const: type_of::default_substs_for_anon_const, opt_const_param_of: type_of::opt_const_param_of, type_of: type_of::type_of, item_bounds: item_bounds::item_bounds, @@ -1309,7 +1310,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // FIXME(#43408) always enable this once `lazy_normalization` is // stable enough and does not need a feature gate anymore. Node::AnonConst(_) => { - let parent_id = tcx.hir().get_parent_item(hir_id); + let parent_id = tcx.hir().get_generic_context(hir_id); let parent_def_id = tcx.hir().local_def_id(parent_id); let mut in_param_list = false; diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 88ba5788b05d1..75b5763dc6b6a 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_middle::hir::map::Map; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; +use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable}; use rustc_span::symbol::Ident; @@ -16,6 +16,38 @@ use rustc_span::{Span, DUMMY_SP}; use super::ItemCtxt; use super::{bad_placeholder_type, is_suggestable_infer_ty}; +use crate::AstConv; + +pub(super) fn default_substs_for_anon_const<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> SubstsRef<'tcx> { + let generics = tcx.generics_of(def_id); + let icx = ItemCtxt::new(tcx, def_id.to_def_id()); + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + + if let hir::Node::AnonConst(hir_ct) = tcx.hir().get(hir_id) { + InternalSubsts::for_item(tcx, def_id.to_def_id(), |param, _| { + if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) { + // Our own parameters are the resolved lifetimes. + match param.kind { + ty::GenericParamDefKind::Lifetime => { + if let hir::GenericArg::Lifetime(lifetime) = &hir_ct.generic_args.args[i] { + AstConv::ast_region_to_region(&icx, lifetime, Some(param)).into() + } else { + bug!() + } + } + _ => bug!(), + } + } else { + tcx.mk_param_from_def(param) + } + }) + } else { + bug!("unexpected caller: {:?}", def_id); + } +} /// Computes the relevant generic parameter for a potential generic const argument. /// diff --git a/src/test/ui/const-generics/binders/arr-in-arr.rs b/src/test/ui/const-generics/binders/arr-in-arr.rs new file mode 100644 index 0000000000000..511e04e695af4 --- /dev/null +++ b/src/test/ui/const-generics/binders/arr-in-arr.rs @@ -0,0 +1,17 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Bar<'a, 'b, 'c>(&'a (), &'b (), &'c ()); + +trait Baz<'a, 'b, T> {} + +struct Foo<'a>(&'a ()) where for<'b> [u8; { + let _: Box Baz<'a, 'b, [u8; { + let _: Bar<'a, 'b, 'c>; + 3 + }]>>; + 4 +}]:,; // FIXME(#79356): Add generic bounds here + +fn main() {} diff --git a/src/test/ui/const-generics/binders/const-eval.rs b/src/test/ui/const-generics/binders/const-eval.rs new file mode 100644 index 0000000000000..80cb71be1fd0b --- /dev/null +++ b/src/test/ui/const-generics/binders/const-eval.rs @@ -0,0 +1,17 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Baz {} + +fn test() { + // FIXME(const_generics): This should error. + let _a: Box Baz<{ + let _: &'a (); + std::mem::size_of::() + }>>; +} + +fn main() { + test::(); +} \ No newline at end of file diff --git a/src/test/ui/const-generics/binders/generic_assoc_ty.rs b/src/test/ui/const-generics/binders/generic_assoc_ty.rs new file mode 100644 index 0000000000000..5ebb43d9c8acd --- /dev/null +++ b/src/test/ui/const-generics/binders/generic_assoc_ty.rs @@ -0,0 +1,19 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Foo { + const ASSOC: usize; +} + +impl Foo for &'static () { + const ASSOC: usize = 13; +} + +fn test<'a>() where &'a (): Foo { + let _: [u8; <&'a () as Foo>::ASSOC]; +} + +fn main() { + test(); +} diff --git a/src/test/ui/const-generics/binders/mixed.rs b/src/test/ui/const-generics/binders/mixed.rs new file mode 100644 index 0000000000000..5d3bc28270b96 --- /dev/null +++ b/src/test/ui/const-generics/binders/mixed.rs @@ -0,0 +1,14 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +const fn foo<'a, 'b>() -> usize +where + &'a (): Sized, &'b (): Sized, +{ + 4 +} + +struct Foo<'a>(&'a ()) where for<'b> [u8; foo::<'a, 'b>()]: Sized; + +fn main() {} diff --git a/src/test/ui/const-generics/binders/multiple-lt.rs b/src/test/ui/const-generics/binders/multiple-lt.rs new file mode 100644 index 0000000000000..33048d55bc4c6 --- /dev/null +++ b/src/test/ui/const-generics/binders/multiple-lt.rs @@ -0,0 +1,15 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait A { + fn hey(v: T) -> Self; +} + +impl<'a> A<&'a [u8; 3 + 4]> for &'a u32 { + fn hey(_: &[u8; 3 + 4]) -> &u32 { + &7 + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/binders/simple.rs b/src/test/ui/const-generics/binders/simple.rs index f558adc5fd4e4..48e8a2e50b432 100644 --- a/src/test/ui/const-generics/binders/simple.rs +++ b/src/test/ui/const-generics/binders/simple.rs @@ -1,5 +1,6 @@ +// check-pass #![feature(const_generics)] #![allow(incomplete_features)] -struct Foo where [u8; { let _: &'a (); 3 }]: Sized; +struct Foo(T) where for<'a> [T; { let _: &'a (); 3 }]: Sized; fn main() {} diff --git a/src/test/ui/const-generics/binders/trait-bound.rs b/src/test/ui/const-generics/binders/trait-bound.rs new file mode 100644 index 0000000000000..59acb1bd266c8 --- /dev/null +++ b/src/test/ui/const-generics/binders/trait-bound.rs @@ -0,0 +1,25 @@ +// run-pass +#![feature(const_generics)] +#![feature(lazy_normalization_consts)] +#![allow(incomplete_features)] + +trait EqZero { } + +impl EqZero<0> for () { } + +trait Zero<'a> { + const C: usize; +} + +impl<'a> Zero<'a> for () { + const C: usize = 0; +} + +fn test_me() +where for<'a> T: EqZero<{<() as Zero<'a>>::C}> +{ +} + +fn main() { + test_me::<()>(); +} diff --git a/src/test/ui/const-generics/binders/unused-lt.rs b/src/test/ui/const-generics/binders/unused-lt.rs new file mode 100644 index 0000000000000..1ccec647e1a76 --- /dev/null +++ b/src/test/ui/const-generics/binders/unused-lt.rs @@ -0,0 +1,16 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] +#![deny(unused_lifetimes)] + +// FIXME(const_generics): this should error +fn test<'a>() -> [u8; 3 + 4] { todo!() } + +fn ok1<'a>() -> [u8; { let _: &'a (); 3 }] { todo!() } + +fn ok2<'a>() -> [u8; 3 + 4] { + let _: &'a (); + todo!() +} + +fn main() {} From 3ffbd66a14ea38ee0952c92351857783c02b6df8 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 24 Nov 2020 12:51:08 +0100 Subject: [PATCH 05/10] anon-const, do not add in-band lifetimes --- compiler/rustc_ast_lowering/src/lib.rs | 4 +++- src/test/ui/const-generics/binders/arr-in-arr.rs | 2 +- src/test/ui/const-generics/binders/const-eval.rs | 2 +- src/test/ui/const-generics/binders/in-band-lt.rs | 15 +++++++++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/const-generics/binders/in-band-lt.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a119cb19f8189..774325b0c40ae 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2345,12 +2345,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // but as we already mention the parent generics this is not actually needed. // // Consider only adding explicit higher ranked lifetimes here. + + // We only need `in_scope_lifetimes` because all in-band lifetimes are + // added to the generics of the parent. let lifetime_params: Vec<(Span, ParamName)> = this .in_scope_lifetimes .iter() .cloned() .map(|name| (name.ident().span, name)) - .chain(this.lifetimes_to_define.iter().cloned()) .collect(); let generic_params = diff --git a/src/test/ui/const-generics/binders/arr-in-arr.rs b/src/test/ui/const-generics/binders/arr-in-arr.rs index 511e04e695af4..fbb48d2473122 100644 --- a/src/test/ui/const-generics/binders/arr-in-arr.rs +++ b/src/test/ui/const-generics/binders/arr-in-arr.rs @@ -7,7 +7,7 @@ struct Bar<'a, 'b, 'c>(&'a (), &'b (), &'c ()); trait Baz<'a, 'b, T> {} struct Foo<'a>(&'a ()) where for<'b> [u8; { - let _: Box Baz<'a, 'b, [u8; { + let _: Box Baz<'a, 'b, [u8; { let _: Bar<'a, 'b, 'c>; 3 }]>>; diff --git a/src/test/ui/const-generics/binders/const-eval.rs b/src/test/ui/const-generics/binders/const-eval.rs index 80cb71be1fd0b..da85a51f71260 100644 --- a/src/test/ui/const-generics/binders/const-eval.rs +++ b/src/test/ui/const-generics/binders/const-eval.rs @@ -14,4 +14,4 @@ fn test() { fn main() { test::(); -} \ No newline at end of file +} diff --git a/src/test/ui/const-generics/binders/in-band-lt.rs b/src/test/ui/const-generics/binders/in-band-lt.rs new file mode 100644 index 0000000000000..50170f4f29636 --- /dev/null +++ b/src/test/ui/const-generics/binders/in-band-lt.rs @@ -0,0 +1,15 @@ +// run-pass +#![feature(in_band_lifetimes, const_generics)] +#![allow(incomplete_features)] + +struct Foo(T); + +impl Foo<[u8; { let _: &'a (); 3 }]> { + fn test() -> Self { + Foo([0; 3]) + } +} + +fn main() { + assert_eq!(Foo::test().0, [0; 3]); +} From 0c39eebbfbdf5e167ed0c56b5985c06a1057677f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 24 Nov 2020 13:08:59 +0100 Subject: [PATCH 06/10] only add hrtb as generic params to anon consts --- compiler/rustc_ast_lowering/src/item.rs | 60 +++++---- compiler/rustc_ast_lowering/src/lib.rs | 117 +++++++++++------- .../ui/const-generics/binders/unused-lt.rs | 10 +- .../const-generics/binders/unused-lt.stderr | 14 +++ 4 files changed, 127 insertions(+), 74 deletions(-) create mode 100644 src/test/ui/const-generics/binders/unused-lt.stderr diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index eef6d38aa0584..c37d678f50f80 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,5 +1,5 @@ use super::{AnonymousLifetimeMode, LoweringContext, ParamMode}; -use super::{ImplTraitContext, ImplTraitPosition}; +use super::{ImplTraitContext, ImplTraitPosition, LifetimeOrigin}; use crate::Arena; use rustc_ast::node_id::NodeMap; @@ -420,12 +420,15 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ); - let new_impl_items = - self.with_in_scope_lifetime_defs(&ast_generics.params, |this| { + let new_impl_items = self.with_in_scope_lifetime_defs( + LifetimeOrigin::Other, + &ast_generics.params, + |this| { this.arena.alloc_from_iter( impl_items.iter().map(|item| this.lower_impl_item_ref(item)), ) - }); + }, + ); // `defaultness.has_value()` is never called for an `impl`, always `true` in order // to not cause an assertion failure inside the `lower_defaultness` function. @@ -1430,27 +1433,34 @@ impl<'hir> LoweringContext<'_, 'hir> { ref bounds, span, }) => { - self.with_in_scope_lifetime_defs(&bound_generic_params, |this| { - hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - bound_generic_params: this.lower_generic_params( - bound_generic_params, - &NodeMap::default(), - ImplTraitContext::disallowed(), - ), - bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()), - bounds: this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| { - match *bound { - // Ignore `?Trait` bounds. - // They were copied into type parameters already. - GenericBound::Trait(_, TraitBoundModifier::Maybe) => None, - _ => Some( - this.lower_param_bound(bound, ImplTraitContext::disallowed()), - ), - } - })), - span, - }) - }) + self.with_in_scope_lifetime_defs( + LifetimeOrigin::Hrtb, + &bound_generic_params, + |this| { + hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + bound_generic_params: this.lower_generic_params( + bound_generic_params, + &NodeMap::default(), + ImplTraitContext::disallowed(), + ), + bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()), + bounds: this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| { + match *bound { + // Ignore `?Trait` bounds. + // They were copied into type parameters already. + GenericBound::Trait(_, TraitBoundModifier::Maybe) => None, + _ => { + Some(this.lower_param_bound( + bound, + ImplTraitContext::disallowed(), + )) + } + } + })), + span, + }) + }, + ) } WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 774325b0c40ae..493580f30a5a5 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -155,6 +155,10 @@ struct LoweringContext<'a, 'hir: 'a> { /// We always store a `normalize_to_macros_2_0()` version of the param-name in this /// vector. in_scope_lifetimes: Vec, + /// The index of the first lifetime introduced using `for<'lt>`. + /// + /// Used to only add lifetimes from binders as generics to anon consts. + hrtb_start: Option, current_module: hir::HirId, @@ -168,6 +172,12 @@ struct LoweringContext<'a, 'hir: 'a> { allow_gen_future: Option>, } +#[derive(Copy, Clone)] +enum LifetimeOrigin { + Hrtb, + Other, +} + pub trait ResolverAstLowering { fn def_key(&mut self, id: DefId) -> DefKey; @@ -322,6 +332,7 @@ pub fn lower_crate<'a, 'hir>( lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, in_scope_lifetimes: Vec::new(), + hrtb_start: None, allow_try_trait: Some([sym::try_trait][..].into()), allow_gen_future: Some([sym::gen_future][..].into()), } @@ -853,6 +864,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // for them. fn with_in_scope_lifetime_defs( &mut self, + origin: LifetimeOrigin, params: &[GenericParam], f: impl FnOnce(&mut Self) -> T, ) -> T { @@ -864,9 +876,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => None, }); self.in_scope_lifetimes.extend(lt_def_names); + let hrtb_start = self.hrtb_start; + if matches!(origin, LifetimeOrigin::Hrtb) && self.hrtb_start.is_none() { + self.hrtb_start = Some(old_len); + } let res = f(self); + self.hrtb_start = hrtb_start; self.in_scope_lifetimes.truncate(old_len); res } @@ -885,7 +902,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { f: impl FnOnce(&mut Self, &mut Vec>) -> T, ) -> (hir::Generics<'hir>, T) { let (in_band_defs, (mut lowered_generics, res)) = - self.with_in_scope_lifetime_defs(&generics.params, |this| { + self.with_in_scope_lifetime_defs(LifetimeOrigin::Other, &generics.params, |this| { this.collect_in_band_defs(parent_def_id, anonymous_lifetime_mode, |this| { let mut params = Vec::new(); // Note: it is necessary to lower generics *before* calling `f`. @@ -1225,21 +1242,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx)) } - TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(&f.generic_params, |this| { - this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| { - hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { - generic_params: this.lower_generic_params( - &f.generic_params, - &NodeMap::default(), - ImplTraitContext::disallowed(), - ), - unsafety: this.lower_unsafety(f.unsafety), - abi: this.lower_extern(f.ext), - decl: this.lower_fn_decl(&f.decl, None, false, None), - param_names: this.lower_fn_params_to_names(&f.decl), - })) + TyKind::BareFn(ref f) => { + self.with_in_scope_lifetime_defs(LifetimeOrigin::Hrtb, &f.generic_params, |this| { + this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| { + hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { + generic_params: this.lower_generic_params( + &f.generic_params, + &NodeMap::default(), + ImplTraitContext::disallowed(), + ), + unsafety: this.lower_unsafety(f.unsafety), + abi: this.lower_extern(f.ext), + decl: this.lower_fn_decl(&f.decl, None, false, None), + param_names: this.lower_fn_params_to_names(&f.decl), + })) + }) }) - }), + } TyKind::Never => hir::TyKind::Never, TyKind::Tup(ref tys) => { hir::TyKind::Tup(self.arena.alloc_from_iter( @@ -2243,28 +2262,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { itctx.reborrow(), ); - let trait_ref = self.with_in_scope_lifetime_defs(&p.bound_generic_params, |this| { - // Any impl Trait types defined within this scope can capture - // lifetimes bound on this predicate. - let lt_def_names = p.bound_generic_params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some(hir::LifetimeName::Param( - ParamName::Plain(param.ident.normalize_to_macros_2_0()), - )), - _ => None, - }); - if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx { - capturable_lifetimes.extend(lt_def_names.clone()); - } + let trait_ref = self.with_in_scope_lifetime_defs( + LifetimeOrigin::Hrtb, + &p.bound_generic_params, + |this| { + // Any impl Trait types defined within this scope can capture + // lifetimes bound on this predicate. + let lt_def_names = + p.bound_generic_params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(hir::LifetimeName::Param( + ParamName::Plain(param.ident.normalize_to_macros_2_0()), + )), + _ => None, + }); + if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx + { + capturable_lifetimes.extend(lt_def_names.clone()); + } - let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow()); + let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow()); - if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx { - for param in lt_def_names { - capturable_lifetimes.remove(¶m); + if let ImplTraitContext::OtherOpaqueTy { ref mut capturable_lifetimes, .. } = itctx + { + for param in lt_def_names { + capturable_lifetimes.remove(¶m); + } } - } - res - }); + res + }, + ); hir::PolyTraitRef { bound_generic_params, trait_ref, span: p.span } } @@ -2341,20 +2367,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // We therefore add these lifetimes as additional generic parameters. - // FIXME(const_generics): We currently add all lifetimes as generic params, - // but as we already mention the parent generics this is not actually needed. - // - // Consider only adding explicit higher ranked lifetimes here. - // We only need `in_scope_lifetimes` because all in-band lifetimes are // added to the generics of the parent. - let lifetime_params: Vec<(Span, ParamName)> = this - .in_scope_lifetimes - .iter() - .cloned() - .map(|name| (name.ident().span, name)) - .collect(); - + let lifetime_params: Vec<(Span, ParamName)> = + if let Some(hrtb_start) = this.hrtb_start { + this.in_scope_lifetimes + .iter() + .skip(hrtb_start) + .cloned() + .map(|name| (name.ident().span, name)) + .collect() + } else { + vec![] + }; let generic_params = this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name)| { this.lifetime_to_generic_param(span, hir_name, def_id) diff --git a/src/test/ui/const-generics/binders/unused-lt.rs b/src/test/ui/const-generics/binders/unused-lt.rs index 1ccec647e1a76..923b09b177e9a 100644 --- a/src/test/ui/const-generics/binders/unused-lt.rs +++ b/src/test/ui/const-generics/binders/unused-lt.rs @@ -1,10 +1,12 @@ -// check-pass #![feature(const_generics)] #![allow(incomplete_features)] #![deny(unused_lifetimes)] -// FIXME(const_generics): this should error -fn test<'a>() -> [u8; 3 + 4] { todo!() } +fn err<'a>() -> [u8; 3 + 4] { todo!() } +//~^ ERROR lifetime parameter `'a` never used + +fn hrtb_err() where for<'a> [u8; 3 + 4]: Sized {} +// FIXME(const_generics): This should error fn ok1<'a>() -> [u8; { let _: &'a (); 3 }] { todo!() } @@ -13,4 +15,6 @@ fn ok2<'a>() -> [u8; 3 + 4] { todo!() } +fn hrtb_ok() where for<'a> [u8; { let _: &'a (); 3 }]: Sized {} + fn main() {} diff --git a/src/test/ui/const-generics/binders/unused-lt.stderr b/src/test/ui/const-generics/binders/unused-lt.stderr new file mode 100644 index 0000000000000..250de0bce9387 --- /dev/null +++ b/src/test/ui/const-generics/binders/unused-lt.stderr @@ -0,0 +1,14 @@ +error: lifetime parameter `'a` never used + --> $DIR/unused-lt.rs:5:8 + | +LL | fn err<'a>() -> [u8; 3 + 4] { todo!() } + | -^^- help: elide the unused lifetime + | +note: the lint level is defined here + --> $DIR/unused-lt.rs:3:9 + | +LL | #![deny(unused_lifetimes)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 5b3f8bb8792374b925193bf68ffd6b1e1fc69111 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 24 Nov 2020 13:23:04 +0100 Subject: [PATCH 07/10] hrtb_start safety --- compiler/rustc_ast_lowering/src/lib.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 493580f30a5a5..c750e7e333722 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -876,9 +876,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => None, }); self.in_scope_lifetimes.extend(lt_def_names); + let hrtb_start = self.hrtb_start; - if matches!(origin, LifetimeOrigin::Hrtb) && self.hrtb_start.is_none() { - self.hrtb_start = Some(old_len); + match (hrtb_start, origin) { + (None, LifetimeOrigin::Hrtb) => self.hrtb_start = Some(old_len), + (Some(idx), LifetimeOrigin::Hrtb) => debug_assert!(idx <= old_len), + (None, LifetimeOrigin::Other) => (), + (Some(idx), LifetimeOrigin::Other) => panic!( + "unexpected lifetime origin inside of hrtb: {:?}, hrtb={:?}, new={:?}", + self.in_scope_lifetimes, idx, old_len + ), } let res = f(self); From 23939e498dde84d404ad06f00bde47d269470504 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 24 Nov 2020 13:28:35 +0100 Subject: [PATCH 08/10] cleanup consts --- compiler/rustc_middle/src/ty/consts.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 98760d4e91cc2..c2f433e5b3a01 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -40,17 +40,15 @@ impl<'tcx> Const<'tcx> { let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - let hir_ct = match tcx.hir().get(hir_id) { - hir::Node::AnonConst(ac) => ac, + let body_id = match tcx.hir().get(hir_id) { + hir::Node::AnonConst(ac) => ac.body, _ => span_bug!( tcx.def_span(def.did.to_def_id()), "from_anon_const can only process anonymous constants" ), }; - warn!(?hir_ct.generics, ?hir_ct.generic_args); - - let expr = &tcx.hir().body(hir_ct.body).value; + let expr = &tcx.hir().body(body_id).value; let ty = tcx.type_of(def.def_id_for_type_of()); From 7d9d5992cff903373230bf6d6569c6645deacdcc Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 24 Nov 2020 18:13:26 +0100 Subject: [PATCH 09/10] don't look into anon consts in `FindHirNodeVisitor` --- .../src/infer/error_reporting/need_type_info.rs | 5 +++++ .../associated-item-duplicate-bounds.rs | 7 +++++-- .../associated-item-duplicate-bounds.stderr | 11 +++++------ src/test/ui/issues/issue-39559.rs | 4 +++- src/test/ui/issues/issue-39559.stderr | 9 ++++----- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 373f0a602c0ef..c2c189bdcb394 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -87,6 +87,11 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> { NestedVisitorMap::OnlyBodies(self.infcx.tcx.hir()) } + fn visit_anon_const(&mut self, _ct: &'tcx hir::AnonConst<'tcx>) { + // Do not look into anonymous constants as they are typechecked + // seperately. + } + fn visit_local(&mut self, local: &'tcx Local<'tcx>) { if let (None, Some(ty)) = (self.found_local_pattern, self.node_ty_contains_target(local.hir_id)) diff --git a/src/test/ui/associated-item/associated-item-duplicate-bounds.rs b/src/test/ui/associated-item/associated-item-duplicate-bounds.rs index bec922b0721b9..4c59395182821 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-bounds.rs +++ b/src/test/ui/associated-item/associated-item-duplicate-bounds.rs @@ -1,11 +1,14 @@ +#![feature(min_const_generics)] +// FIXME(const_generics): should be stable soon + trait Adapter { const LINKS: usize; } struct Foo { adapter: A, - links: [u32; A::LINKS], // Shouldn't suggest bounds already there. - //~^ ERROR: no associated item named `LINKS` found + links: [u32; A::LINKS], + //~^ ERROR generic parameters may not be used } fn main() {} diff --git a/src/test/ui/associated-item/associated-item-duplicate-bounds.stderr b/src/test/ui/associated-item/associated-item-duplicate-bounds.stderr index ff1ad4c006e78..0b84718424d29 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-bounds.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-bounds.stderr @@ -1,11 +1,10 @@ -error[E0599]: no associated item named `LINKS` found for type parameter `A` in the current scope - --> $DIR/associated-item-duplicate-bounds.rs:7:21 +error: generic parameters may not be used in const operations + --> $DIR/associated-item-duplicate-bounds.rs:10:18 | -LL | links: [u32; A::LINKS], // Shouldn't suggest bounds already there. - | ^^^^^ associated item not found in `A` +LL | links: [u32; A::LINKS], + | ^^^^^^^^ cannot perform const operation using `A` | - = help: items from traits can only be used if the type parameter is bounded by the trait + = note: type parameters may not be used in const expressions error: aborting due to previous error -For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/issues/issue-39559.rs b/src/test/ui/issues/issue-39559.rs index 3a75956af5280..d99c04c65485a 100644 --- a/src/test/ui/issues/issue-39559.rs +++ b/src/test/ui/issues/issue-39559.rs @@ -1,3 +1,5 @@ +#![feature(min_const_generics)] +// FIXME(const_generics): This should be stabilized soon enough trait Dim { fn dim() -> usize; } @@ -12,7 +14,7 @@ impl Dim for Dim3 { pub struct Vector { entries: [T; D::dim()], - //~^ ERROR no function or associated item named `dim` found + //~^ ERROR generic parameters may not be used _dummy: D, } diff --git a/src/test/ui/issues/issue-39559.stderr b/src/test/ui/issues/issue-39559.stderr index 5e8d487f41658..a82ba12d98787 100644 --- a/src/test/ui/issues/issue-39559.stderr +++ b/src/test/ui/issues/issue-39559.stderr @@ -1,11 +1,10 @@ -error[E0599]: no function or associated item named `dim` found for type parameter `D` in the current scope - --> $DIR/issue-39559.rs:14:21 +error: generic parameters may not be used in const operations + --> $DIR/issue-39559.rs:16:18 | LL | entries: [T; D::dim()], - | ^^^ function or associated item not found in `D` + | ^^^^^^ cannot perform const operation using `D` | - = help: items from traits can only be used if the type parameter is bounded by the trait + = note: type parameters may not be used in const expressions error: aborting due to previous error -For more information about this error, try `rustc --explain E0599`. From 7c44a22e74b525138fa293af19f6a698a28d9c17 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 24 Nov 2020 18:50:45 +0100 Subject: [PATCH 10/10] rebase --- compiler/rustc_ast_lowering/src/lib.rs | 17 ++++++++--------- compiler/rustc_resolve/src/late/lifetimes.rs | 16 ++++++++++------ .../associated-item-duplicate-bounds.stderr | 1 + src/test/ui/issues/issue-39559.stderr | 1 + 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c750e7e333722..3a8e94343e5cc 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -523,13 +523,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => visit::walk_ty(self, t), } } - - fn visit_anon_const(&mut self, ct: &'tcx AnonConst) { - self.lctx.allocate_hir_id_counter(ct.id); - self.with_hir_id_owner(Some(ct.id), |this| { - visit::walk_anon_const(this, ct); - }); - } } self.lower_node_id(CRATE_NODE_ID); @@ -2401,7 +2394,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) })); - hir::AnonConst { + // The generics of an anonymous constants refer to the + // generics of their parent anon const, so we only have to + // deal with each higher ranked lifetime at the outermost const. + let hrtb_start = mem::replace(&mut this.hrtb_start, None); + let ct = hir::AnonConst { hir_id, generics: hir::Generics { params: generic_params, @@ -2414,7 +2411,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { parenthesized: false, }, body: this.lower_const_body(c.value.span, Some(&c.value)), - } + }; + this.hrtb_start = hrtb_start; + ct }) }) } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 31a993aef988e..614d2a56bf046 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1577,12 +1577,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } fn check_uses_for_lifetimes_defined_by_scope(&mut self) { - let defined_by = match self.scope { - Scope::Binder { from_anon_const: true, .. } => { - debug!("check_uses_for_lifetimes_defined_by_scope: synthetic anon const binder"); - return; - } - Scope::Binder { lifetimes, .. } => lifetimes, + let (defined_by, from_anon_const) = match self.scope { + &Scope::Binder { ref lifetimes, from_anon_const, .. } => (lifetimes, from_anon_const), _ => { debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope"); return; @@ -1600,6 +1596,14 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { }) .collect(); + if from_anon_const { + debug!("check_uses_for_lifetimes_defined_by_scope: synthetic anon const"); + for def_id in def_ids { + self.lifetime_uses.remove(&def_id); + } + return; + } + // ensure that we issue lints in a repeatable order def_ids.sort_by_cached_key(|&def_id| self.tcx.def_path_hash(def_id)); diff --git a/src/test/ui/associated-item/associated-item-duplicate-bounds.stderr b/src/test/ui/associated-item/associated-item-duplicate-bounds.stderr index 0b84718424d29..e61357312b162 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-bounds.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-bounds.stderr @@ -5,6 +5,7 @@ LL | links: [u32; A::LINKS], | ^^^^^^^^ cannot perform const operation using `A` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to previous error diff --git a/src/test/ui/issues/issue-39559.stderr b/src/test/ui/issues/issue-39559.stderr index a82ba12d98787..0685c63c8e06d 100644 --- a/src/test/ui/issues/issue-39559.stderr +++ b/src/test/ui/issues/issue-39559.stderr @@ -5,6 +5,7 @@ LL | entries: [T; D::dim()], | ^^^^^^ cannot perform const operation using `D` | = note: type parameters may not be used in const expressions + = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: aborting due to previous error