Rollup merge of #107489 - compiler-errors:non_lifetime_binders, r=cjgillot

Implement partial support for non-lifetime binders

This implements support for non-lifetime binders. It's pretty useless currently, but I wanted to put this up so the implementation can be discussed.

Specifically, this piggybacks off of the late-bound lifetime collection code in `rustc_hir_typeck::collect::lifetimes`. This seems like a necessary step given the fact we don't resolve late-bound regions until this point, and binders are sometimes merged.

Q: I'm not sure if I should go along this route, or try to modify the earlier nameres code to compute the right bound var indices for type and const binders eagerly... If so, I'll need to rename all these queries to something more appropriate (I've done this for `resolve_lifetime::Region` -> `resolve_lifetime::ResolvedArg`)

cc rust-lang/types-team#81

r? `@ghost`
This commit is contained in:
Matthias Krüger 2023-02-17 00:19:34 +01:00 committed by GitHub
commit 089e8c03bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 709 additions and 343 deletions

View file

@ -294,27 +294,6 @@ fn check_trait_fn_not_const(&self, constness: Const) {
}
}
fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
// Check only lifetime parameters are present and that the lifetime
// parameters that are present have no bounds.
let non_lt_param_spans: Vec<_> = params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
if !param.bounds.is_empty() {
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
self.session.emit_err(ForbiddenLifetimeBound { spans });
}
None
}
_ => Some(param.ident.span),
})
.collect();
if !non_lt_param_spans.is_empty() {
self.session.emit_err(ForbiddenNonLifetimeParam { spans: non_lt_param_spans });
}
}
fn check_fn_decl(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
self.check_decl_num_args(fn_decl);
self.check_decl_cvaradic_pos(fn_decl);
@ -745,7 +724,6 @@ fn visit_ty_common(&mut self, ty: &'a Ty) {
)
.emit();
});
self.check_late_bound_lifetime_defs(&bfty.generic_params);
if let Extern::Implicit(_) = bfty.ext {
let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
self.maybe_lint_missing_abi(sig_span, ty.id);
@ -1318,9 +1296,6 @@ fn visit_generics(&mut self, generics: &'a Generics) {
for predicate in &generics.where_clause.predicates {
match predicate {
WherePredicate::BoundPredicate(bound_pred) => {
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
// This is slightly complicated. Our representation for poly-trait-refs contains a single
// binder and thus we only allow a single level of quantification. However,
// the syntax of Rust permits quantification in two places in where clauses,
@ -1396,11 +1371,6 @@ fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
visit::walk_param_bound(self, bound)
}
fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
visit::walk_poly_trait_ref(self, t);
}
fn visit_variant_data(&mut self, s: &'a VariantData) {
self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
}
@ -1437,10 +1407,6 @@ fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
.emit();
}
if let FnKind::Closure(ClosureBinder::For { generic_params, .. }, ..) = fk {
self.check_late_bound_lifetime_defs(generic_params);
}
if let FnKind::Fn(
_,
_,

View file

@ -11,6 +11,8 @@
use rustc_span::Span;
use rustc_target::spec::abi;
use crate::errors::ForbiddenLifetimeBound;
macro_rules! gate_feature_fn {
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
let (visitor, has_feature, span, name, explain, help) =
@ -136,6 +138,34 @@ fn visit_ty(&mut self, ty: &ast::Ty) {
}
ImplTraitVisitor { vis: self }.visit_ty(ty);
}
fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) {
// Check only lifetime parameters are present and that the lifetime
// parameters that are present have no bounds.
let non_lt_param_spans: Vec<_> = params
.iter()
.filter_map(|param| match param.kind {
ast::GenericParamKind::Lifetime { .. } => None,
_ => Some(param.ident.span),
})
.collect();
// FIXME: gate_feature_post doesn't really handle multispans...
if !non_lt_param_spans.is_empty() && !self.features.non_lifetime_binders {
feature_err(
&self.sess.parse_sess,
sym::non_lifetime_binders,
non_lt_param_spans,
rustc_errors::fluent::ast_passes_forbidden_non_lifetime_param,
)
.emit();
}
for param in params {
if !param.bounds.is_empty() {
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
self.sess.emit_err(ForbiddenLifetimeBound { spans });
}
}
}
}
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
@ -147,7 +177,7 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
..
}) = attr_info
{
gate_feature_fn!(self, has_feature, attr.span, *name, descr);
gate_feature_fn!(self, has_feature, attr.span, *name, *descr);
}
// Check unstable flavors of the `#[doc]` attribute.
if attr.has_name(sym::doc) {
@ -306,6 +336,7 @@ fn visit_ty(&mut self, ty: &'a ast::Ty) {
ast::TyKind::BareFn(bare_fn_ty) => {
// Function pointers cannot be `const`
self.check_extern(bare_fn_ty.ext, ast::Const::No);
self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params);
}
ast::TyKind::Never => {
gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental");
@ -318,6 +349,19 @@ fn visit_ty(&mut self, ty: &'a ast::Ty) {
visit::walk_ty(self, ty)
}
fn visit_generics(&mut self, g: &'a ast::Generics) {
for predicate in &g.where_clause.predicates {
match predicate {
ast::WherePredicate::BoundPredicate(bound_pred) => {
// A type binding, eg `for<'c> Foo: Send+Clone+'c`
self.check_late_bound_lifetime_defs(&bound_pred.bound_generic_params);
}
_ => {}
}
}
visit::walk_generics(self, g);
}
fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FnRetTy) {
if let ast::FnRetTy::Ty(output_ty) = ret_ty {
if let ast::TyKind::Never = output_ty.kind {
@ -437,12 +481,21 @@ fn visit_pat(&mut self, pattern: &'a ast::Pat) {
visit::walk_pat(self, pattern)
}
fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
visit::walk_poly_trait_ref(self, t);
}
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
if let Some(header) = fn_kind.header() {
// Stability of const fn methods are covered in `visit_assoc_item` below.
self.check_extern(header.ext, header.constness);
}
if let FnKind::Closure(ast::ClosureBinder::For { generic_params, .. }, ..) = fn_kind {
self.check_late_bound_lifetime_defs(generic_params);
}
if fn_kind.ctxt() != Some(FnCtxt::Foreign) && fn_kind.decl().c_variadic() {
gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable");
}

View file

@ -731,7 +731,7 @@ pub fn eval_condition(
sess,
sym::cfg_target_compact,
cfg.span,
&"compact `cfg(target(..))` is experimental and subject to change"
"compact `cfg(target(..))` is experimental and subject to change"
).emit();
}

View file

@ -473,6 +473,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
(active, no_sanitize, "1.42.0", Some(39699), None),
/// Allows using the `non_exhaustive_omitted_patterns` lint.
(active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
/// Allows `for<T>` binders in where-clauses
(incomplete, non_lifetime_binders, "CURRENT_RUSTC_VERSION", Some(1), None),
/// Allows making `dyn Trait` well-formed even if `Trait` is not object safe.
/// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
/// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.

View file

@ -14,7 +14,7 @@
AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits,
TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified,
};
use crate::middle::resolve_lifetime as rl;
use crate::middle::resolve_bound_vars as rbv;
use crate::require_c_abi_if_c_variadic;
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@ -225,10 +225,10 @@ pub fn ast_region_to_region(
let tcx = self.tcx();
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,
match tcx.named_bound_var(lifetime.hir_id) {
Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static,
Some(rl::Region::LateBound(debruijn, index, def_id)) => {
Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => {
let name = lifetime_name(def_id.expect_local());
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(index),
@ -237,7 +237,7 @@ pub fn ast_region_to_region(
tcx.mk_re_late_bound(debruijn, br)
}
Some(rl::Region::EarlyBound(def_id)) => {
Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
let name = tcx.hir().ty_param_name(def_id.expect_local());
let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
let generics = tcx.generics_of(item_def_id);
@ -245,7 +245,7 @@ pub fn ast_region_to_region(
tcx.mk_re_early_bound(ty::EarlyBoundRegion { def_id, index, name })
}
Some(rl::Region::Free(scope, id)) => {
Some(rbv::ResolvedArg::Free(scope, id)) => {
let name = lifetime_name(id.expect_local());
tcx.mk_re_free(scope, ty::BrNamed(id, name))
@ -1607,7 +1607,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
self.ast_region_to_region(lifetime, None)
} else {
self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
if tcx.named_region(lifetime.hir_id).is_some() {
if tcx.named_bound_var(lifetime.hir_id).is_some() {
self.ast_region_to_region(lifetime, None)
} else {
self.re_infer(None, span).unwrap_or_else(|| {
@ -2600,6 +2600,7 @@ pub fn res_to_ty(
&self,
opt_self_ty: Option<Ty<'tcx>>,
path: &hir::Path<'_>,
hir_id: hir::HirId,
permit_variants: bool,
) -> Ty<'tcx> {
let tcx = self.tcx();
@ -2663,11 +2664,25 @@ pub fn res_to_ty(
}
});
let def_id = def_id.expect_local();
let item_def_id = tcx.hir().ty_param_owner(def_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
match tcx.named_bound_var(hir_id) {
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
let name =
tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local()));
let br = ty::BoundTy {
var: ty::BoundVar::from_u32(index),
kind: ty::BoundTyKind::Param(def_id, name),
};
tcx.mk_ty(ty::Bound(debruijn, br))
}
Some(rbv::ResolvedArg::EarlyBound(_)) => {
let def_id = def_id.expect_local();
let item_def_id = tcx.hir().ty_param_owner(def_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
}
arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
}
}
Res::SelfTyParam { .. } => {
// `Self` in trait or type alias.
@ -2870,14 +2885,22 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
hir::TyKind::BareFn(bf) => {
require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
tcx.mk_fn_ptr(self.ty_of_fn(
let fn_ptr_ty = tcx.mk_fn_ptr(self.ty_of_fn(
ast_ty.hir_id,
bf.unsafety,
bf.abi,
bf.decl,
None,
Some(ast_ty),
))
));
if let Some(guar) =
deny_non_region_late_bound(tcx, bf.generic_params, "function pointer")
{
tcx.ty_error_with_guaranteed(guar)
} else {
fn_ptr_ty
}
}
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
self.maybe_lint_bare_trait(ast_ty, in_path);
@ -2885,12 +2908,27 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
TraitObjectSyntax::DynStar => ty::DynStar,
};
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr)
let object_ty = self.conv_object_ty_poly_trait_ref(
ast_ty.span,
bounds,
lifetime,
borrowed,
repr,
);
if let Some(guar) = bounds.iter().find_map(|trait_ref| {
deny_non_region_late_bound(tcx, trait_ref.bound_generic_params, "trait object")
}) {
tcx.ty_error_with_guaranteed(guar)
} else {
object_ty
}
}
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
debug!(?maybe_qself, ?path);
let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself));
self.res_to_ty(opt_self_ty, path, false)
self.res_to_ty(opt_self_ty, path, ast_ty.hir_id, false)
}
&hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
let opaque_ty = tcx.hir().item(item_id);
@ -3346,3 +3384,24 @@ fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
}
}
}
fn deny_non_region_late_bound(
tcx: TyCtxt<'_>,
params: &[hir::GenericParam<'_>],
where_: &str,
) -> Option<ErrorGuaranteed> {
params.iter().find_map(|bad_param| {
let what = match bad_param.kind {
hir::GenericParamKind::Type { .. } => "type",
hir::GenericParamKind::Const { .. } => "const",
hir::GenericParamKind::Lifetime { .. } => return None,
};
let mut diag = tcx.sess.struct_span_err(
bad_param.span,
format!("late-bound {what} parameter not allowed on {where_} types"),
);
Some(if tcx.features().non_lifetime_binders { diag.emit() } else { diag.delay_as_bug() })
})
}

View file

@ -41,8 +41,8 @@
mod generics_of;
mod item_bounds;
mod lifetimes;
mod predicates_of;
mod resolve_bound_vars;
mod type_of;
///////////////////////////////////////////////////////////////////////////
@ -53,7 +53,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
}
pub fn provide(providers: &mut Providers) {
lifetimes::provide(providers);
resolve_bound_vars::provide(providers);
*providers = Providers {
opt_const_param_of: type_of::opt_const_param_of,
type_of: type_of::type_of,

View file

@ -1,4 +1,4 @@
use crate::middle::resolve_lifetime as rl;
use crate::middle::resolve_bound_vars as rbv;
use hir::{
intravisit::{self, Visitor},
GenericParamKind, HirId, Node,
@ -394,10 +394,11 @@ fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
return;
}
match self.tcx.named_region(lt.hir_id) {
Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {}
Some(rl::Region::LateBound(debruijn, _, _)) if debruijn < self.outer_index => {}
Some(rl::Region::LateBound(..) | rl::Region::Free(..)) | None => {
match self.tcx.named_bound_var(lt.hir_id) {
Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {}
Some(rbv::ResolvedArg::LateBound(debruijn, _, _))
if debruijn < self.outer_index => {}
Some(rbv::ResolvedArg::LateBound(..) | rbv::ResolvedArg::Free(..)) | None => {
self.has_late_bound_regions = Some(lt.ident.span);
}
}

View file

@ -16,7 +16,7 @@
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeName, Node};
use rustc_middle::bug;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::*;
use rustc_middle::middle::resolve_bound_vars::*;
use rustc_middle::ty::{self, ir::TypeVisitor, DefIdTree, TyCtxt, TypeSuperVisitable};
use rustc_span::def_id::DefId;
use rustc_span::symbol::{sym, Ident};
@ -24,59 +24,61 @@
use std::fmt;
trait RegionExt {
fn early(param: &GenericParam<'_>) -> (LocalDefId, Region);
fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
fn late(index: u32, param: &GenericParam<'_>) -> (LocalDefId, Region);
fn late(index: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg);
fn id(&self) -> Option<DefId>;
fn shifted(self, amount: u32) -> Region;
fn shifted(self, amount: u32) -> ResolvedArg;
}
impl RegionExt for Region {
fn early(param: &GenericParam<'_>) -> (LocalDefId, Region) {
debug!("Region::early: def_id={:?}", param.def_id);
(param.def_id, Region::EarlyBound(param.def_id.to_def_id()))
impl RegionExt for ResolvedArg {
fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
debug!("ResolvedArg::early: def_id={:?}", param.def_id);
(param.def_id, ResolvedArg::EarlyBound(param.def_id.to_def_id()))
}
fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, Region) {
fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
let depth = ty::INNERMOST;
debug!(
"Region::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
"ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
idx, param, depth, param.def_id,
);
(param.def_id, Region::LateBound(depth, idx, param.def_id.to_def_id()))
(param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id.to_def_id()))
}
fn id(&self) -> Option<DefId> {
match *self {
Region::Static => None,
ResolvedArg::StaticLifetime => None,
Region::EarlyBound(id) | Region::LateBound(_, _, id) | Region::Free(_, id) => Some(id),
ResolvedArg::EarlyBound(id)
| ResolvedArg::LateBound(_, _, id)
| ResolvedArg::Free(_, id) => Some(id),
}
}
fn shifted(self, amount: u32) -> Region {
fn shifted(self, amount: u32) -> ResolvedArg {
match self {
Region::LateBound(debruijn, idx, id) => {
Region::LateBound(debruijn.shifted_in(amount), idx, id)
ResolvedArg::LateBound(debruijn, idx, id) => {
ResolvedArg::LateBound(debruijn.shifted_in(amount), idx, id)
}
_ => self,
}
}
}
/// Maps the id of each lifetime reference to the lifetime decl
/// Maps the id of each bound variable reference to the variable decl
/// that it corresponds to.
///
/// FIXME. This struct gets converted to a `ResolveLifetimes` for
/// FIXME. This struct gets converted to a `ResolveBoundVars` for
/// actual use. It has the same data, but indexed by `LocalDefId`. This
/// is silly.
#[derive(Debug, Default)]
struct NamedRegionMap {
// maps from every use of a named (not anonymous) lifetime to a
// `Region` describing how that region is bound
defs: HirIdMap<Region>,
struct NamedVarMap {
// maps from every use of a named (not anonymous) bound var to a
// `ResolvedArg` describing how that variable is bound
defs: HirIdMap<ResolvedArg>,
// Maps relevant hir items to the bound vars on them. These include:
// - function defs
@ -87,9 +89,9 @@ struct NamedRegionMap {
late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>,
}
struct LifetimeContext<'a, 'tcx> {
struct BoundVarContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
map: &'a mut NamedRegionMap,
map: &'a mut NamedVarMap,
scope: ScopeRef<'a>,
}
@ -102,7 +104,7 @@ enum Scope<'a> {
Binder {
/// We use an IndexMap here because we want these lifetimes in order
/// for diagnostics.
lifetimes: FxIndexMap<LocalDefId, Region>,
bound_vars: FxIndexMap<LocalDefId, ResolvedArg>,
scope_type: BinderScopeType,
@ -141,7 +143,7 @@ enum Scope<'a> {
/// inferred in a function body or potentially error outside one),
/// for the default choice of lifetime in a trait object type.
ObjectLifetimeDefault {
lifetime: Option<Region>,
lifetime: Option<ResolvedArg>,
s: ScopeRef<'a>,
},
@ -150,7 +152,7 @@ enum Scope<'a> {
/// lifetimes encountered when identifying the trait that an associated type
/// is declared on.
Supertrait {
lifetimes: Vec<ty::BoundVariableKind>,
bound_vars: Vec<ty::BoundVariableKind>,
s: ScopeRef<'a>,
},
@ -185,9 +187,9 @@ enum BinderScopeType {
impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
Scope::Binder { lifetimes, scope_type, hir_id, where_bound_origin, s: _ } => f
Scope::Binder { bound_vars, scope_type, hir_id, where_bound_origin, s: _ } => f
.debug_struct("Binder")
.field("lifetimes", lifetimes)
.field("bound_vars", bound_vars)
.field("scope_type", scope_type)
.field("hir_id", hir_id)
.field("where_bound_origin", where_bound_origin)
@ -202,9 +204,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
.field("lifetime", lifetime)
.field("s", &"..")
.finish(),
Scope::Supertrait { lifetimes, s: _ } => f
Scope::Supertrait { bound_vars, s: _ } => f
.debug_struct("Supertrait")
.field("lifetimes", lifetimes)
.field("bound_vars", bound_vars)
.field("s", &"..")
.finish(),
Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(),
@ -219,27 +221,27 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
pub(crate) fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
resolve_lifetimes,
resolve_bound_vars,
named_region_map: |tcx, id| tcx.resolve_lifetimes(id).defs.get(&id),
named_variable_map: |tcx, id| tcx.resolve_bound_vars(id).defs.get(&id),
is_late_bound_map,
object_lifetime_default,
late_bound_vars_map: |tcx, id| tcx.resolve_lifetimes(id).late_bound_vars.get(&id),
late_bound_vars_map: |tcx, id| tcx.resolve_bound_vars(id).late_bound_vars.get(&id),
..*providers
};
}
/// Computes the `ResolveLifetimes` map that contains data for an entire `Item`.
/// Computes the `ResolveBoundVars` map that contains data for an entire `Item`.
/// You should not read the result of this query directly, but rather use
/// `named_region_map`, `is_late_bound_map`, etc.
/// `named_variable_map`, `is_late_bound_map`, etc.
#[instrument(level = "debug", skip(tcx))]
fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveLifetimes {
let mut named_region_map =
NamedRegionMap { defs: Default::default(), late_bound_vars: Default::default() };
let mut visitor = LifetimeContext {
fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars {
let mut named_variable_map =
NamedVarMap { defs: Default::default(), late_bound_vars: Default::default() };
let mut visitor = BoundVarContext {
tcx,
map: &mut named_region_map,
map: &mut named_variable_map,
scope: &Scope::Root { opt_parent_item: None },
};
match tcx.hir().owner(local_def_id) {
@ -260,13 +262,13 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveLife
hir::OwnerNode::Crate(_) => {}
}
let mut rl = ResolveLifetimes::default();
let mut rl = ResolveBoundVars::default();
for (hir_id, v) in named_region_map.defs {
for (hir_id, v) in named_variable_map.defs {
let map = rl.defs.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v);
}
for (hir_id, v) in named_region_map.late_bound_vars {
for (hir_id, v) in named_variable_map.late_bound_vars {
let map = rl.late_bound_vars.entry(hir_id.owner).or_default();
map.insert(hir_id.local_id, v);
}
@ -276,21 +278,33 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveLife
rl
}
fn late_region_as_bound_region(tcx: TyCtxt<'_>, region: &Region) -> ty::BoundVariableKind {
match region {
Region::LateBound(_, _, def_id) => {
fn late_arg_as_bound_arg<'tcx>(
tcx: TyCtxt<'tcx>,
arg: &ResolvedArg,
param: &GenericParam<'tcx>,
) -> ty::BoundVariableKind {
match arg {
ResolvedArg::LateBound(_, _, def_id) => {
let name = tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local()));
ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name))
match param.kind {
GenericParamKind::Lifetime { .. } => {
ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name))
}
GenericParamKind::Type { .. } => {
ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(*def_id, name))
}
GenericParamKind::Const { .. } => ty::BoundVariableKind::Const,
}
}
_ => bug!("{:?} is not a late region", region),
_ => bug!("{:?} is not a late argument", arg),
}
}
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
/// Returns the binders in scope and the type of `Binder` that should be created for a poly trait ref.
fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderScopeType) {
let mut scope = self.scope;
let mut supertrait_lifetimes = vec![];
let mut supertrait_bound_vars = vec![];
loop {
match scope {
Scope::Body { .. } | Scope::Root { .. } => {
@ -301,14 +315,14 @@ fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderS
scope = s;
}
Scope::Supertrait { s, lifetimes } => {
supertrait_lifetimes = lifetimes.clone();
Scope::Supertrait { s, bound_vars } => {
supertrait_bound_vars = bound_vars.clone();
scope = s;
}
Scope::TraitRefBoundary { .. } => {
// We should only see super trait lifetimes if there is a `Binder` above
assert!(supertrait_lifetimes.is_empty());
assert!(supertrait_bound_vars.is_empty());
break (vec![], BinderScopeType::Normal);
}
@ -316,14 +330,14 @@ fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderS
// Nested poly trait refs have the binders concatenated
let mut full_binders =
self.map.late_bound_vars.entry(*hir_id).or_default().clone();
full_binders.extend(supertrait_lifetimes.into_iter());
full_binders.extend(supertrait_bound_vars.into_iter());
break (full_binders, BinderScopeType::Concatenating);
}
}
}
}
}
impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
type NestedFilter = nested_filter::OnlyBodies;
fn nested_visit_map(&mut self) -> Self::Map {
@ -386,14 +400,13 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
}
}
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) =
let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
bound_generic_params
.iter()
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(late_bound_idx as u32, param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
let pair = ResolvedArg::late(late_bound_idx as u32, param);
let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
(pair, r)
})
.unzip();
@ -401,7 +414,7 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
self.record_late_bound_vars(e.hir_id, binders);
let scope = Scope::Binder {
hir_id: e.hir_id,
lifetimes,
bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
@ -461,7 +474,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
// conservatively add all resolved lifetimes. Otherwise we run into problems in
// cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
let parent_item = self.tcx.hir().get_parent_item(item.hir_id());
let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(parent_item);
let resolved_lifetimes: &ResolveBoundVars =
self.tcx.resolve_bound_vars(parent_item);
// We need to add *all* deps, since opaque tys may want them from *us*
for (&owner, defs) in resolved_lifetimes.defs.iter() {
defs.iter().for_each(|(&local_id, region)| {
@ -478,35 +492,33 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
}
}
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_),
origin: hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent),
generics,
..
}) => {
// We want to start our early-bound indices at the end of the parent scope,
// not including any parent `impl Trait`s.
let mut lifetimes = FxIndexMap::default();
let mut bound_vars = FxIndexMap::default();
debug!(?generics.params);
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {
let (def_id, reg) = Region::early(&param);
lifetimes.insert(def_id, reg);
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {}
}
let (def_id, reg) = ResolvedArg::early(&param);
bound_vars.insert(def_id, reg);
}
let scope = Scope::Binder {
hir_id: item.hir_id(),
lifetimes,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
};
let scope = Scope::Root { opt_parent_item: Some(parent) };
self.with(scope, |this| {
let scope = Scope::TraitRefBoundary { s: this.scope };
this.with(scope, |this| intravisit::walk_item(this, item))
});
let scope = Scope::Binder {
hir_id: item.hir_id(),
bound_vars,
s: this.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
};
this.with(scope, |this| {
let scope = Scope::TraitRefBoundary { s: this.scope };
this.with(scope, |this| intravisit::walk_item(this, item))
});
})
}
hir::ItemKind::TyAlias(_, generics)
| hir::ItemKind::Enum(_, generics)
@ -516,18 +528,11 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
| hir::ItemKind::TraitAlias(generics, ..)
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
// These kinds of items have only early-bound lifetime parameters.
let lifetimes = generics
.params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
})
.collect();
let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
self.record_late_bound_vars(item.hir_id(), vec![]);
let scope = Scope::Binder {
hir_id: item.hir_id(),
lifetimes,
bound_vars,
scope_type: BinderScopeType::Normal,
s: self.scope,
where_bound_origin: None,
@ -562,21 +567,20 @@ fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
match ty.kind {
hir::TyKind::BareFn(c) => {
let (lifetimes, binders): (FxIndexMap<LocalDefId, Region>, Vec<_>) = c
let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = c
.generic_params
.iter()
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(late_bound_idx as u32, param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
let pair = ResolvedArg::late(late_bound_idx as u32, param);
let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
(pair, r)
})
.unzip();
self.record_late_bound_vars(ty.hir_id, binders);
let scope = Scope::Binder {
hir_id: ty.hir_id,
lifetimes,
bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
@ -674,7 +678,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
// well-supported at the moment, so this doesn't work.
// In the future, this should be fixed and this error should be removed.
let def = self.map.defs.get(&lifetime.hir_id).cloned();
let Some(Region::LateBound(_, _, def_id)) = def else {
let Some(ResolvedArg::LateBound(_, _, def_id)) = def else {
continue
};
let Some(def_id) = def_id.as_local() else {
@ -722,18 +726,11 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
}
Type(bounds, ty) => {
let generics = &trait_item.generics;
let lifetimes = generics
.params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
})
.collect();
let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
self.record_late_bound_vars(trait_item.hir_id(), vec![]);
let scope = Scope::Binder {
hir_id: trait_item.hir_id(),
lifetimes,
bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
@ -768,18 +765,12 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
}),
Type(ty) => {
let generics = &impl_item.generics;
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
.params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(Region::early(param)),
GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => None,
})
.collect();
let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> =
generics.params.iter().map(ResolvedArg::early).collect();
self.record_late_bound_vars(impl_item.hir_id(), vec![]);
let scope = Scope::Binder {
hir_id: impl_item.hir_id(),
lifetimes,
bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
@ -803,7 +794,9 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
#[instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
match lifetime_ref.res {
hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static),
hir::LifetimeName::Static => {
self.insert_lifetime(lifetime_ref, ResolvedArg::StaticLifetime)
}
hir::LifetimeName::Param(param_def_id) => {
self.resolve_lifetime_ref(param_def_id, lifetime_ref)
}
@ -814,13 +807,16 @@ fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
}
}
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
fn visit_path(&mut self, path: &hir::Path<'tcx>, hir_id: hir::HirId) {
for (i, segment) in path.segments.iter().enumerate() {
let depth = path.segments.len() - i - 1;
if let Some(args) = segment.args {
self.visit_segment_args(path.res, depth, args);
}
}
if let Res::Def(DefKind::TyParam | DefKind::ConstParam, param_def_id) = path.res {
self.resolve_type_ref(param_def_id.expect_local(), hir_id);
}
}
fn visit_fn(
@ -869,24 +865,17 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
origin,
..
}) => {
let lifetimes: FxIndexMap<LocalDefId, Region> =
let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
bound_generic_params
.iter()
.filter(|param| {
matches!(param.kind, GenericParamKind::Lifetime { .. })
})
.enumerate()
.map(|(late_bound_idx, param)| {
Region::late(late_bound_idx as u32, param)
})
.collect();
let binders: Vec<_> =
lifetimes
.iter()
.map(|(_, region)| {
late_region_as_bound_region(this.tcx, region)
})
.collect();
.iter()
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = ResolvedArg::late(late_bound_idx as u32, param);
let r = late_arg_as_bound_arg(this.tcx, &pair.1, param);
(pair, r)
})
.unzip();
this.record_late_bound_vars(hir_id, binders.clone());
// Even if there are no lifetimes defined here, we still wrap it in a binder
// scope. If there happens to be a nested poly trait ref (an error), that
@ -894,7 +883,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
// being wrong.
let scope = Scope::Binder {
hir_id,
lifetimes,
bound_vars,
s: this.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: Some(origin),
@ -920,7 +909,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
if lt.res != hir::LifetimeName::Static {
continue;
}
this.insert_lifetime(lt, Region::Static);
this.insert_lifetime(lt, ResolvedArg::StaticLifetime);
this.tcx
.sess
.struct_span_warn(
@ -964,7 +953,7 @@ fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) {
self.record_late_bound_vars(*hir_id, binders);
let scope = Scope::Binder {
hir_id: *hir_id,
lifetimes: FxIndexMap::default(),
bound_vars: FxIndexMap::default(),
s: self.scope,
scope_type,
where_bound_origin: None,
@ -983,16 +972,12 @@ fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) {
let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
let initial_bound_vars = binders.len() as u32;
let mut lifetimes: FxIndexMap<LocalDefId, Region> = FxIndexMap::default();
let binders_iter = trait_ref
.bound_generic_params
.iter()
.filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(initial_bound_vars + late_bound_idx as u32, param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
lifetimes.insert(pair.0, pair.1);
let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = FxIndexMap::default();
let binders_iter =
trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| {
let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
bound_vars.insert(pair.0, pair.1);
r
});
binders.extend(binders_iter);
@ -1006,7 +991,7 @@ fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) {
// refs.
let scope = Scope::Binder {
hir_id: trait_ref.trait_ref.hir_ref_id,
lifetimes,
bound_vars,
s: self.scope,
scope_type,
where_bound_origin: None,
@ -1063,13 +1048,13 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifeti
}
}
impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
fn with<F>(&mut self, wrap_scope: Scope<'_>, f: F)
where
F: for<'b> FnOnce(&mut LifetimeContext<'b, 'tcx>),
F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>),
{
let LifetimeContext { tcx, map, .. } = self;
let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope };
let BoundVarContext { tcx, map, .. } = self;
let mut this = BoundVarContext { tcx: *tcx, map, scope: &wrap_scope };
let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope));
{
let _enter = span.enter();
@ -1110,23 +1095,25 @@ fn visit_early_late<F>(
generics: &'tcx hir::Generics<'tcx>,
walk: F,
) where
F: for<'b, 'c> FnOnce(&'b mut LifetimeContext<'c, 'tcx>),
F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>),
{
let mut named_late_bound_vars = 0;
let lifetimes: FxIndexMap<LocalDefId, Region> = generics
let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = generics
.params
.iter()
.filter_map(|param| match param.kind {
.map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => {
if self.tcx.is_late_bound(param.hir_id) {
let late_bound_idx = named_late_bound_vars;
named_late_bound_vars += 1;
Some(Region::late(late_bound_idx, param))
ResolvedArg::late(late_bound_idx, param)
} else {
Some(Region::early(param))
ResolvedArg::early(param)
}
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
ResolvedArg::early(param)
}
})
.collect();
@ -1139,14 +1126,14 @@ fn visit_early_late<F>(
})
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(late_bound_idx as u32, param);
late_region_as_bound_region(self.tcx, &pair.1)
let pair = ResolvedArg::late(late_bound_idx as u32, param);
late_arg_as_bound_arg(self.tcx, &pair.1, param)
})
.collect();
self.record_late_bound_vars(hir_id, binders);
let scope = Scope::Binder {
hir_id,
lifetimes,
bound_vars,
s: self.scope,
scope_type: BinderScopeType::Normal,
where_bound_origin: None,
@ -1177,15 +1164,15 @@ fn resolve_lifetime_ref(
Scope::Root { opt_parent_item } => {
if let Some(parent_item) = opt_parent_item
&& let parent_generics = self.tcx.generics_of(parent_item)
&& parent_generics.param_def_id_to_index.contains_key(&region_def_id.to_def_id())
&& parent_generics.param_def_id_to_index(self.tcx, region_def_id.to_def_id()).is_some()
{
break Some(Region::EarlyBound(region_def_id.to_def_id()));
break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id()));
}
break None;
}
Scope::Binder { ref lifetimes, scope_type, s, where_bound_origin, .. } => {
if let Some(&def) = lifetimes.get(&region_def_id) {
Scope::Binder { ref bound_vars, scope_type, s, where_bound_origin, .. } => {
if let Some(&def) = bound_vars.get(&region_def_id) {
break Some(def.shifted(late_depth));
}
match scope_type {
@ -1259,7 +1246,7 @@ fn resolve_lifetime_ref(
};
if let Some(mut def) = result {
if let Region::EarlyBound(..) = def {
if let ResolvedArg::EarlyBound(..) = def {
// Do not free early-bound regions, only late-bound ones.
} else if let Some(body_id) = outermost_body {
let fn_id = self.tcx.hir().body_owner(body_id);
@ -1275,10 +1262,10 @@ fn resolve_lifetime_ref(
kind: hir::ImplItemKind::Fn(..),
..
}) => {
def = Region::Free(owner_id.to_def_id(), def.id().unwrap());
def = ResolvedArg::Free(owner_id.to_def_id(), def.id().unwrap());
}
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) => {
def = Region::Free(closure.def_id.to_def_id(), def.id().unwrap());
def = ResolvedArg::Free(closure.def_id.to_def_id(), def.id().unwrap());
}
_ => {}
}
@ -1329,6 +1316,57 @@ fn resolve_lifetime_ref(
);
}
fn resolve_type_ref(&mut self, param_def_id: LocalDefId, hir_id: hir::HirId) {
// Walk up the scope chain, tracking the number of fn scopes
// that we pass through, until we find a lifetime with the
// given name or we run out of scopes.
// search.
let mut late_depth = 0;
let mut scope = self.scope;
let result = loop {
match *scope {
Scope::Body { s, .. } => {
scope = s;
}
Scope::Root { opt_parent_item } => {
if let Some(parent_item) = opt_parent_item
&& let parent_generics = self.tcx.generics_of(parent_item)
&& parent_generics.param_def_id_to_index(self.tcx, param_def_id.to_def_id()).is_some()
{
break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id()));
}
break None;
}
Scope::Binder { ref bound_vars, scope_type, s, .. } => {
if let Some(&def) = bound_vars.get(&param_def_id) {
break Some(def.shifted(late_depth));
}
match scope_type {
BinderScopeType::Normal => late_depth += 1,
BinderScopeType::Concatenating => {}
}
scope = s;
}
Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. } => {
scope = s;
}
}
};
if let Some(def) = result {
self.map.defs.insert(hir_id, def);
return;
}
span_bug!(self.tcx.hir().span(hir_id), "could not resolve {param_def_id:?}",);
}
#[instrument(level = "debug", skip(self))]
fn visit_segment_args(
&mut self,
@ -1415,10 +1453,10 @@ fn visit_segment_args(
if in_body {
None
} else {
Some(Region::Static)
Some(ResolvedArg::StaticLifetime)
}
}
ObjectLifetimeDefault::Static => Some(Region::Static),
ObjectLifetimeDefault::Static => Some(ResolvedArg::StaticLifetime),
ObjectLifetimeDefault::Param(param_def_id) => {
// This index can be used with `generic_args` since `parent_count == 0`.
let index = generics.param_def_id_to_index[&param_def_id] as usize;
@ -1507,18 +1545,19 @@ fn visit_segment_args(
// in the trait ref `YY<...>` in `Item: YY<...>`.
for binding in generic_args.bindings {
let scope = Scope::ObjectLifetimeDefault {
lifetime: if has_lifetime_parameter { None } else { Some(Region::Static) },
lifetime: if has_lifetime_parameter {
None
} else {
Some(ResolvedArg::StaticLifetime)
},
s: self.scope,
};
if let Some(type_def_id) = type_def_id {
let lifetimes = LifetimeContext::supertrait_hrtb_lifetimes(
self.tcx,
type_def_id,
binding.ident,
);
let bound_vars =
BoundVarContext::supertrait_hrtb_vars(self.tcx, type_def_id, binding.ident);
self.with(scope, |this| {
let scope = Scope::Supertrait {
lifetimes: lifetimes.unwrap_or_default(),
bound_vars: bound_vars.unwrap_or_default(),
s: this.scope,
};
this.with(scope, |this| this.visit_assoc_type_binding(binding));
@ -1541,7 +1580,7 @@ fn visit_segment_args(
/// ```
/// In this case, if we wanted to the supertrait HRTB lifetimes for `As` on
/// the starting trait `Bar`, we would return `Some(['b, 'a])`.
fn supertrait_hrtb_lifetimes(
fn supertrait_hrtb_vars(
tcx: TyCtxt<'tcx>,
def_id: DefId,
assoc_name: Ident,
@ -1626,7 +1665,7 @@ fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime)
scope = s;
}
Scope::Root { .. } | Scope::Elision { .. } => break Region::Static,
Scope::Root { .. } | Scope::Elision { .. } => break ResolvedArg::StaticLifetime,
Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
@ -1641,7 +1680,7 @@ fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime)
}
#[instrument(level = "debug", skip(self))]
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: ResolvedArg) {
debug!(span = ?lifetime_ref.ident.span);
self.map.defs.insert(lifetime_ref.hir_id, def);
}
@ -1649,7 +1688,11 @@ fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
/// Sometimes we resolve a lifetime, but later find that it is an
/// error (esp. around impl trait). In that case, we remove the
/// entry into `map.defs` so as not to confuse later code.
fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_def: Region) {
fn uninsert_lifetime_on_error(
&mut self,
lifetime_ref: &'tcx hir::Lifetime,
bad_def: ResolvedArg,
) {
let old_value = self.map.defs.remove(&lifetime_ref.hir_id);
assert_eq!(old_value, Some(bad_def));
}

View file

@ -1740,7 +1740,7 @@ fn finish_resolving_struct_path(
match *qpath {
QPath::Resolved(ref maybe_qself, ref path) => {
let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw);
let ty = self.astconv().res_to_ty(self_ty, path, true);
let ty = self.astconv().res_to_ty(self_ty, path, hir_id, true);
(path.res, self.handle_raw_ty(path_span, ty))
}
QPath::TypeRelative(ref qself, ref segment) => {

View file

@ -2,7 +2,7 @@
use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::middle::resolve_bound_vars as rbv;
use rustc_middle::ty::{self, Region, TyCtxt};
/// This function calls the `visit_ty` method for the parameters
@ -99,11 +99,11 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
hir::TyKind::Ref(ref lifetime, _) => {
// the lifetime of the Ref
let hir_id = lifetime.hir_id;
match (self.tcx.named_region(hir_id), self.bound_region) {
match (self.tcx.named_bound_var(hir_id), self.bound_region) {
// Find the index of the named region that was part of the
// error. We will then search the function parameters for a bound
// region at the right depth with the same index
(Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
(Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
if id == def_id {
self.found_type = Some(arg);
@ -115,7 +115,7 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
// error. We will then search the function parameters for a bound
// region at the right depth with the same index
(
Some(rl::Region::LateBound(debruijn_index, _, id)),
Some(rbv::ResolvedArg::LateBound(debruijn_index, _, id)),
ty::BrNamed(def_id, _),
) => {
debug!(
@ -131,10 +131,10 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
(
Some(
rl::Region::Static
| rl::Region::Free(_, _)
| rl::Region::EarlyBound(_)
| rl::Region::LateBound(_, _, _),
rbv::ResolvedArg::StaticLifetime
| rbv::ResolvedArg::Free(_, _)
| rbv::ResolvedArg::EarlyBound(_)
| rbv::ResolvedArg::LateBound(_, _, _),
)
| None,
_,
@ -186,9 +186,9 @@ fn nested_visit_map(&mut self) -> Map<'tcx> {
}
fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
match (self.tcx.named_bound_var(lifetime.hir_id), self.bound_region) {
// the lifetime of the TyPath!
(Some(rl::Region::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
(Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
if id == def_id {
self.found_it = true;
@ -196,7 +196,7 @@ fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
}
}
(Some(rl::Region::LateBound(debruijn_index, _, id)), ty::BrNamed(def_id, _)) => {
(Some(rbv::ResolvedArg::LateBound(debruijn_index, _, id)), ty::BrNamed(def_id, _)) => {
debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,);
debug!("id={:?}", id);
debug!("def_id={:?}", def_id);
@ -208,10 +208,10 @@ fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
(
Some(
rl::Region::Static
| rl::Region::EarlyBound(_)
| rl::Region::LateBound(_, _, _)
| rl::Region::Free(_, _),
rbv::ResolvedArg::StaticLifetime
| rbv::ResolvedArg::EarlyBound(_)
| rbv::ResolvedArg::LateBound(_, _, _)
| rbv::ResolvedArg::Free(_, _),
)
| None,
_,

View file

@ -2007,7 +2007,7 @@ fn collect_outlives_bound_spans<'tcx>(
inferred_outlives: &[ty::Region<'tcx>],
predicate_span: Span,
) -> Vec<(usize, Span)> {
use rustc_middle::middle::resolve_lifetime::Region;
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
bounds
.iter()
@ -2017,8 +2017,8 @@ fn collect_outlives_bound_spans<'tcx>(
return None;
};
let is_inferred = match tcx.named_region(lifetime.hir_id) {
Some(Region::EarlyBound(def_id)) => inferred_outlives
let is_inferred = match tcx.named_bound_var(lifetime.hir_id) {
Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives
.iter()
.any(|r| matches!(**r, ty::ReEarlyBound(ebr) if { ebr.def_id == def_id })),
_ => false,
@ -2097,7 +2097,7 @@ fn consolidate_outlives_bound_spans(
impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
use rustc_middle::middle::resolve_lifetime::Region;
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
let def_id = item.owner_id.def_id;
if let hir::ItemKind::Struct(_, hir_generics)
@ -2120,8 +2120,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let (relevant_lifetimes, bounds, predicate_span, in_where_clause) =
match where_predicate {
hir::WherePredicate::RegionPredicate(predicate) => {
if let Some(Region::EarlyBound(region_def_id)) =
cx.tcx.named_region(predicate.lifetime.hir_id)
if let Some(ResolvedArg::EarlyBound(region_def_id)) =
cx.tcx.named_bound_var(predicate.lifetime.hir_id)
{
(
Self::lifetimes_outliving_lifetime(

View file

@ -18,7 +18,7 @@
use rustc_middle::metadata::ModChild;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
use rustc_middle::mir;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::query::Providers;

View file

@ -29,7 +29,7 @@ pub fn to_vec(&self) -> Vec<(Symbol, Option<Symbol>)> {
pub mod limits;
pub mod privacy;
pub mod region;
pub mod resolve_lifetime;
pub mod resolve_bound_vars;
pub mod stability;
pub fn provide(providers: &mut crate::ty::query::Providers) {

View file

@ -1,4 +1,4 @@
//! Name resolution for lifetimes: type declarations.
//! Name resolution for lifetimes and late-bound type and const variables: type declarations.
use crate::ty;
@ -8,10 +8,10 @@
use rustc_macros::HashStable;
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)]
pub enum Region {
Static,
EarlyBound(/* lifetime decl */ DefId),
LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* lifetime decl */ DefId),
pub enum ResolvedArg {
StaticLifetime,
EarlyBound(/* decl */ DefId),
LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ DefId),
Free(DefId, /* lifetime decl */ DefId),
}
@ -46,10 +46,10 @@ pub enum ObjectLifetimeDefault {
/// Maps the id of each lifetime reference to the lifetime decl
/// that it corresponds to.
#[derive(Default, HashStable, Debug)]
pub struct ResolveLifetimes {
pub struct ResolveBoundVars {
/// Maps from every use of a named (not anonymous) lifetime to a
/// `Region` describing how that region is bound
pub defs: FxHashMap<OwnerId, FxHashMap<ItemLocalId, Region>>,
pub defs: FxHashMap<OwnerId, FxHashMap<ItemLocalId, ResolvedArg>>,
pub late_bound_vars: FxHashMap<OwnerId, FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>>,
}

View file

@ -1641,12 +1641,12 @@
/// Does lifetime resolution on items. Importantly, we can't resolve
/// lifetimes directly on things like trait methods, because of trait params.
/// See `rustc_resolve::late::lifetimes for details.
query resolve_lifetimes(_: hir::OwnerId) -> &'tcx ResolveLifetimes {
query resolve_bound_vars(_: hir::OwnerId) -> &'tcx ResolveBoundVars {
arena_cache
desc { "resolving lifetimes" }
}
query named_region_map(_: hir::OwnerId) ->
Option<&'tcx FxHashMap<ItemLocalId, Region>> {
query named_variable_map(_: hir::OwnerId) ->
Option<&'tcx FxHashMap<ItemLocalId, ResolvedArg>> {
desc { "looking up a named region" }
}
query is_late_bound_map(_: hir::OwnerId) -> Option<&'tcx FxIndexSet<ItemLocalId>> {

View file

@ -1,7 +1,9 @@
use crate::middle::resolve_bound_vars as rbv;
use crate::mir::interpret::LitToConstInput;
use crate::ty::{self, DefIdTree, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
use rustc_data_structures::intern::Interned;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_macros::HashStable;
use std::fmt;
@ -125,16 +127,27 @@ fn try_eval_lit_or_param(
}
}
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
match expr.kind {
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
// Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`.
let item_def_id = tcx.parent(def_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.item_name(def_id);
Some(tcx.mk_const(ty::ParamConst::new(index, name), ty))
hir::ExprKind::Path(hir::QPath::Resolved(
_,
&hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. },
)) => {
match tcx.named_bound_var(expr.hir_id) {
Some(rbv::ResolvedArg::EarlyBound(_)) => {
// Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`.
let item_def_id = tcx.parent(def_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.item_name(def_id);
Some(tcx.mk_const(ty::ParamConst::new(index, name), ty))
}
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => Some(tcx.mk_const(
ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)),
ty,
)),
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id),
}
}
_ => None,
}

View file

@ -9,7 +9,7 @@
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use crate::lint::struct_lint_level;
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
use crate::middle::resolve_lifetime;
use crate::middle::resolve_bound_vars;
use crate::middle::stability;
use crate::mir::interpret::{self, Allocation, ConstAllocation};
use crate::mir::{
@ -2368,9 +2368,9 @@ pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> {
Some(&*candidates)
}
pub fn named_region(self, id: HirId) -> Option<resolve_lifetime::Region> {
pub fn named_bound_var(self, id: HirId) -> Option<resolve_bound_vars::ResolvedArg> {
debug!(?id, "named_region");
self.named_region_map(id.owner).and_then(|map| map.get(&id.local_id).cloned())
self.named_variable_map(id.owner).and_then(|map| map.get(&id.local_id).cloned())
}
pub fn is_late_bound(self, id: HirId) -> bool {

View file

@ -290,7 +290,7 @@ pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -
// Impls cannot contain these types as these cannot be named directly.
ty::FnDef(..) | ty::Closure(..) | ty::Generator(..) => false,
ty::Placeholder(..) => false,
ty::Placeholder(..) | ty::Bound(..) => false,
// Depending on the value of `treat_obligation_params`, we either
// treat generic parameters like placeholders or like inference variables.
@ -310,7 +310,7 @@ pub fn types_may_unify<'tcx>(self, obligation_ty: Ty<'tcx>, impl_ty: Ty<'tcx>) -
ty::Error(_) => true,
ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) | ty::Bound(..) => {
ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) => {
bug!("unexpected obligation type: {:?}", obligation_ty)
}
}

View file

@ -57,7 +57,7 @@ impl $crate::ty::ParameterizedOverTcx for $ty {
crate::metadata::ModChild,
crate::middle::codegen_fn_attrs::CodegenFnAttrs,
crate::middle::exported_symbols::SymbolExportInfo,
crate::middle::resolve_lifetime::ObjectLifetimeDefault,
crate::middle::resolve_bound_vars::ObjectLifetimeDefault,
crate::mir::ConstQualifs,
ty::AssocItemContainer,
ty::DeducedParamAttrs,

View file

@ -6,7 +6,7 @@
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
use crate::middle::lib_features::LibFeatures;
use crate::middle::privacy::EffectiveVisibilities;
use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes};
use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg};
use crate::middle::stability::{self, DeprecationEntry};
use crate::mir;
use crate::mir::interpret::GlobalId;

View file

@ -2,7 +2,7 @@
use rustc_data_structures::graph::dominators::Dominators;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_middle::middle::resolve_lifetime::Set1;
use rustc_middle::middle::resolve_bound_vars::Set1;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::ty::{ParamEnv, TyCtxt};

View file

@ -18,7 +18,7 @@
};
use rustc_hir::{MethodKind, Target, Unsafety};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{ParamEnv, TyCtxt};

View file

@ -270,10 +270,11 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
| ty::Ref(..)
| ty::FnPtr(..)
| ty::Param(..)
| ty::Bound(..)
| ty::Error(_)
| ty::GeneratorWitness(..)
| ty::GeneratorWitnessMIR(..) => {}
ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => {
ty::Placeholder(..) | ty::Infer(..) => {
bug!("unexpected type: {:?}", ty)
}
}

View file

@ -21,7 +21,7 @@
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
use rustc_middle::middle::resolve_lifetime::Set1;
use rustc_middle::middle::resolve_bound_vars::Set1;
use rustc_middle::ty::DefIdTree;
use rustc_middle::{bug, span_bug};
use rustc_session::config::{CrateType, ResolveDocLinks};
@ -2505,7 +2505,13 @@ fn with_generic_param_rib<'c, F>(
let res = match kind {
ItemRibKind(..) | AssocItemRibKind => Res::Def(def_kind, def_id.to_def_id()),
NormalRibKind => Res::Err,
NormalRibKind => {
if self.r.session.features_untracked().non_lifetime_binders {
Res::Def(def_kind, def_id.to_def_id())
} else {
Res::Err
}
}
_ => span_bug!(param.ident.span, "Unexpected rib kind {:?}", kind),
};
self.r.record_partial_res(param.id, PartialRes::new(res));

View file

@ -4,7 +4,7 @@
use crate::parse::ParseSess;
use rustc_ast::token;
use rustc_ast::util::literal::LitError;
use rustc_errors::MultiSpan;
use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan};
use rustc_macros::Diagnostic;
use rustc_span::{Span, Symbol};
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
@ -27,12 +27,22 @@ pub struct CguNotRecorded<'a> {
pub cgu_name: &'a str,
}
#[derive(Diagnostic)]
#[diag(session_feature_gate_error, code = "E0658")]
pub struct FeatureGateError<'a> {
#[primary_span]
pub struct FeatureGateError {
pub span: MultiSpan,
pub explain: &'a str,
pub explain: DiagnosticMessage,
}
impl<'a, T: EmissionGuarantee> IntoDiagnostic<'a, T> for FeatureGateError {
#[track_caller]
fn into_diagnostic(
self,
handler: &'a rustc_errors::Handler,
) -> rustc_errors::DiagnosticBuilder<'a, T> {
let mut diag = handler.struct_diagnostic(self.explain);
diag.set_span(self.span);
diag.code(error_code!(E0658));
diag
}
}
#[derive(Subdiagnostic)]

View file

@ -88,7 +88,7 @@ pub fn feature_err<'a>(
sess: &'a ParseSess,
feature: Symbol,
span: impl Into<MultiSpan>,
explain: &str,
explain: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
feature_err_issue(sess, feature, span, GateIssue::Language, explain)
}
@ -103,7 +103,7 @@ pub fn feature_err_issue<'a>(
feature: Symbol,
span: impl Into<MultiSpan>,
issue: GateIssue,
explain: &str,
explain: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let span = span.into();
@ -114,7 +114,7 @@ pub fn feature_err_issue<'a>(
.map(|err| err.cancel());
}
let mut err = sess.create_err(FeatureGateError { span, explain });
let mut err = sess.create_err(FeatureGateError { span, explain: explain.into() });
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
err
}

View file

@ -1016,6 +1016,7 @@
non_ascii_idents,
non_exhaustive,
non_exhaustive_omitted_patterns_lint,
non_lifetime_binders,
non_modrs_mods,
nontemporal_store,
noop_method_borrow,

View file

@ -60,7 +60,7 @@ fn impl_similar_to(
) -> Option<(DefId, SubstsRef<'tcx>)> {
let tcx = self.tcx;
let param_env = obligation.param_env;
let trait_ref = tcx.erase_late_bound_regions(trait_ref);
let trait_ref = self.instantiate_binder_with_placeholders(trait_ref);
let trait_self_ty = trait_ref.self_ty();
let mut self_match_impls = vec![];

View file

@ -1056,7 +1056,7 @@ fn suggest_add_clone_to_arg(
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
let ty = self.tcx.erase_late_bound_regions(self_ty);
let ty = self.instantiate_binder_with_placeholders(self_ty);
let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else { return false };
let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };
let ty::Param(param) = inner_ty.kind() else { return false };

View file

@ -396,7 +396,10 @@ fn assemble_candidates_from_auto_impls(
// still be provided by a manual implementation for
// this trait and type.
}
ty::Param(..) | ty::Alias(ty::Projection, ..) => {
ty::Param(..)
| ty::Alias(ty::Projection, ..)
| ty::Placeholder(..)
| ty::Bound(..) => {
// In these cases, we don't know what the actual
// type is. Therefore, we cannot break it down
// into its constituent types. So we don't
@ -448,6 +451,10 @@ fn assemble_candidates_from_object_ty(
);
self.infcx.probe(|_snapshot| {
if obligation.has_non_region_late_bound() {
return;
}
// The code below doesn't care about regions, and the
// self-ty here doesn't escape this probe, so just erase
// any LBR.

View file

@ -21,7 +21,7 @@
use rustc_hir::PredicateOrigin;
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::middle::resolve_bound_vars as rbv;
use rustc_middle::ty::fold::ir::TypeFolder;
use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::TypeVisitable;
@ -200,11 +200,11 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
}
fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
let def = cx.tcx.named_region(lifetime.hir_id);
let def = cx.tcx.named_bound_var(lifetime.hir_id);
if let Some(
rl::Region::EarlyBound(node_id)
| rl::Region::LateBound(_, _, node_id)
| rl::Region::Free(_, node_id),
rbv::ResolvedArg::EarlyBound(node_id)
| rbv::ResolvedArg::LateBound(_, _, node_id)
| rbv::ResolvedArg::Free(_, node_id),
) = def
{
if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {

View file

@ -505,13 +505,13 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
if let FnRetTy::Return(ty) = sig.decl.output
&& let Some((out, Mutability::Mut, _)) = get_ref_lm(ty)
{
let out_region = cx.tcx.named_region(out.hir_id);
let out_region = cx.tcx.named_bound_var(out.hir_id);
let args: Option<Vec<_>> = sig
.decl
.inputs
.iter()
.filter_map(get_ref_lm)
.filter(|&(lt, _, _)| cx.tcx.named_region(lt.hir_id) == out_region)
.filter(|&(lt, _, _)| cx.tcx.named_bound_var(lt.hir_id) == out_region)
.map(|(_, mutability, span)| (mutability == Mutability::Not).then_some(span))
.collect();
if let Some(args) = args

View file

@ -16,17 +16,24 @@ error: lifetime bounds cannot be used in this context
LL | type C = for<'b, 'a: 'b +> fn();
| ^^
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/bounds-lifetime.rs:4:18
|
LL | type D = for<'a, T> fn();
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/bounds-lifetime.rs:5:18
|
LL | type E = dyn for<T> Fn();
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,8 +1,12 @@
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/disallow-const.rs:4:15
|
LL | for<const N: i32> || -> () {};
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,8 +1,12 @@
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/disallow-ty.rs:4:9
|
LL | for<T> || -> () {};
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,21 +1,3 @@
error: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:7:45
|
LL | type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn();
| ^
error: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:11:51
|
LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy;
| ^
error: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:15:54
|
LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy;
| ^
error: cannot find attribute `unknown` in this scope
--> $DIR/cfg-generic-params.rs:19:29
|
@ -46,5 +28,33 @@ error: cannot find attribute `unknown` in this scope
LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
| ^^^^^^^
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:7:45
|
LL | type FnBad = for<#[cfg(no)] 'a, #[cfg(yes)] T> fn();
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:11:51
|
LL | type PolyBad = dyn for<#[cfg(no)] 'a, #[cfg(yes)] T> Copy;
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:15:54
|
LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy;
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,4 @@
fn foo() where for<T> T:, {}
//~^ ERROR only lifetime parameters can be used in this context
fn main() {}

View file

@ -0,0 +1,12 @@
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/feature-gate-non_lifetime_binders.rs:1:20
|
LL | fn foo() where for<T> T:, {}
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,14 +1,21 @@
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/hrtb-wrong-kind.rs:1:18
|
LL | fn a() where for<T> T: Copy {}
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: only lifetime parameters can be used in this context
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/hrtb-wrong-kind.rs:4:24
|
LL | fn b() where for<const C: usize> [(); C]: Copy {}
| ^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(non_lifetime_binders)]` to the crate attributes to enable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -88,12 +88,6 @@ error: expected identifier, found `>`
LL | type QuiteBroken = fn<const>();
| ^ expected identifier
error: lifetime bounds cannot be used in this context
--> $DIR/recover-fn-ptr-with-generics.rs:22:26
|
LL | let _: extern fn<'a: 'static>();
| ^^^^^^^
error[E0412]: cannot find type `T` in this scope
--> $DIR/recover-fn-ptr-with-generics.rs:5:27
|
@ -106,6 +100,12 @@ error[E0412]: cannot find type `T` in this scope
LL | type Identity = fn<T>(T) -> T;
| ^ not found in this scope
error: lifetime bounds cannot be used in this context
--> $DIR/recover-fn-ptr-with-generics.rs:22:26
|
LL | let _: extern fn<'a: 'static>();
| ^^^^^^^
error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0412`.

View file

@ -0,0 +1,19 @@
// check-pass
// Basic test that show's we can succesfully typeck a `for<T>` where clause.
#![feature(non_lifetime_binders)]
//~^ WARN the feature `non_lifetime_binders` is incomplete
trait Trait {}
impl<T: ?Sized> Trait for T {}
fn foo()
where
for<T> T: Trait,
{
}
fn main() {
foo();
}

View file

@ -0,0 +1,11 @@
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/basic.rs:4:12
|
LL | #![feature(non_lifetime_binders)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View file

@ -0,0 +1,23 @@
// Error reporting for where `for<T> T: Trait` doesn't hold
#![feature(non_lifetime_binders)]
//~^ WARN the feature `non_lifetime_binders` is incomplete
trait Trait {}
fn fail()
where
for<T> T: Trait,
{}
fn auto_trait()
where
for<T> T: Send,
{}
fn main() {
fail();
//~^ ERROR the trait bound `T: Trait` is not satisfied
auto_trait();
//~^ ERROR `T` cannot be sent between threads safely
}

View file

@ -0,0 +1,43 @@
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/fail.rs:3:12
|
LL | #![feature(non_lifetime_binders)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: the trait bound `T: Trait` is not satisfied
--> $DIR/fail.rs:19:5
|
LL | fail();
| ^^^^ the trait `Trait` is not implemented for `T`
|
note: required by a bound in `fail`
--> $DIR/fail.rs:10:15
|
LL | fn fail()
| ---- required by a bound in this
LL | where
LL | for<T> T: Trait,
| ^^^^^ required by this bound in `fail`
error[E0277]: `T` cannot be sent between threads safely
--> $DIR/fail.rs:21:5
|
LL | auto_trait();
| ^^^^^^^^^^ `T` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `T`
note: required by a bound in `auto_trait`
--> $DIR/fail.rs:15:15
|
LL | fn auto_trait()
| ---------- required by a bound in this
LL | where
LL | for<T> T: Send,
| ^^^^ required by this bound in `auto_trait`
error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,13 @@
// Tests to make sure that we reject polymorphic dyn trait.
#![feature(non_lifetime_binders)]
//~^ WARN the feature `non_lifetime_binders` is incomplete
trait Test<T> {}
fn foo() -> &'static dyn for<T> Test<T> {
//~^ ERROR late-bound type parameter not allowed on trait object types
todo!()
}
fn main() {}

View file

@ -0,0 +1,17 @@
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/on-dyn.rs:3:12
|
LL | #![feature(non_lifetime_binders)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= note: `#[warn(incomplete_features)]` on by default
error: late-bound type parameter not allowed on trait object types
--> $DIR/on-dyn.rs:8:30
|
LL | fn foo() -> &'static dyn for<T> Test<T> {
| ^
error: aborting due to previous error; 1 warning emitted

View file

@ -0,0 +1,13 @@
// Tests to make sure that we reject polymorphic fn ptrs.
#![feature(non_lifetime_binders)]
//~^ WARN the feature `non_lifetime_binders` is incomplete
fn foo() -> for<T> fn(T) {
//~^ ERROR late-bound type parameter not allowed on function pointer types
todo!()
}
fn main() {
foo()(1i32);
}

View file

@ -0,0 +1,17 @@
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/on-ptr.rs:3:12
|
LL | #![feature(non_lifetime_binders)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= note: `#[warn(incomplete_features)]` on by default
error: late-bound type parameter not allowed on function pointer types
--> $DIR/on-ptr.rs:6:17
|
LL | fn foo() -> for<T> fn(T) {
| ^
error: aborting due to previous error; 1 warning emitted