Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implement partial support for non-lifetime binders #107489

Merged
merged 6 commits into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Make things actually work
  • Loading branch information
compiler-errors committed Feb 16, 2023
commit 52f82354dc1dee723b0b1324dda7ddeabc332830
27 changes: 21 additions & 6 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2598,6 +2598,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
opt_self_ty: Option<Ty<'tcx>>,
path: &hir::Path<'_>,
hir_id: hir::HirId,
permit_variants: bool,
) -> Ty<'tcx> {
let tcx = self.tcx();
Expand Down Expand Up @@ -2661,11 +2662,25 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
});

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.
Expand Down Expand Up @@ -2888,7 +2903,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
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);
Expand Down
203 changes: 120 additions & 83 deletions compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ trait RegionExt {

impl RegionExt for ResolvedArg {
fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
debug!("Region::early: def_id={:?}", param.def_id);
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, 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, ResolvedArg::LateBound(depth, idx, param.def_id.to_def_id()))
Expand Down Expand Up @@ -278,13 +278,25 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou
rl
}

fn late_region_as_bound_region(tcx: TyCtxt<'_>, region: &ResolvedArg) -> ty::BoundVariableKind {
match region {
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 argument", region),
_ => bug!("{:?} is not a late argument", arg),
}
}

Expand Down Expand Up @@ -391,11 +403,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
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 = ResolvedArg::late(late_bound_idx as u32, param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
(pair, r)
})
.unzip();
Expand Down Expand Up @@ -481,7 +492,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
}
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_),
origin: hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent),
generics,
..
}) => {
Expand All @@ -490,26 +501,24 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
let mut bound_vars = FxIndexMap::default();
debug!(?generics.params);
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {
let (def_id, reg) = ResolvedArg::early(&param);
bound_vars.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(),
bound_vars,
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)
Expand All @@ -519,14 +528,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
| hir::ItemKind::TraitAlias(generics, ..)
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
// These kinds of items have only early-bound lifetime parameters.
let bound_vars = generics
.params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(ResolvedArg::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(),
Expand Down Expand Up @@ -568,11 +570,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
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 = ResolvedArg::late(late_bound_idx as u32, param);
let r = late_region_as_bound_region(self.tcx, &pair.1);
let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
(pair, r)
})
.unzip();
Expand Down Expand Up @@ -725,14 +726,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
Type(bounds, ty) => {
let generics = &trait_item.generics;
let bound_vars = generics
.params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(ResolvedArg::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(),
Expand Down Expand Up @@ -771,14 +765,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}),
Type(ty) => {
let generics = &impl_item.generics;
let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = generics
.params
.iter()
.filter_map(|param| match param.kind {
GenericParamKind::Lifetime { .. } => Some(ResolvedArg::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(),
Expand Down Expand Up @@ -819,13 +807,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
}

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(
Expand Down Expand Up @@ -874,24 +865,17 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
origin,
..
}) => {
let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> =

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)| {
ResolvedArg::late(late_bound_idx as u32, param)
})
.collect();
let binders: Vec<_> =
bound_vars
.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
Expand Down Expand Up @@ -989,14 +973,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {

let initial_bound_vars = binders.len() as u32;
let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = 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 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_region_as_bound_region(self.tcx, &pair.1);
let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
bound_vars.insert(pair.0, pair.1);
r
});
Expand Down Expand Up @@ -1121,17 +1101,19 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
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(ResolvedArg::late(late_bound_idx, param))
ResolvedArg::late(late_bound_idx, param)
} else {
Some(ResolvedArg::early(param))
ResolvedArg::early(param)
}
}
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => None,
GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
ResolvedArg::early(param)
}
})
.collect();

Expand All @@ -1145,7 +1127,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = ResolvedArg::late(late_bound_idx as u32, param);
late_region_as_bound_region(self.tcx, &pair.1)
late_arg_as_bound_arg(self.tcx, &pair.1, param)
})
.collect();
self.record_late_bound_vars(hir_id, binders);
Expand Down Expand Up @@ -1182,7 +1164,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
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(ResolvedArg::EarlyBound(region_def_id.to_def_id()));
}
Expand Down Expand Up @@ -1334,6 +1316,61 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
);
}

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:?}, scopes: {:#?}",
self.scope
);
}

#[instrument(level = "debug", skip(self))]
fn visit_segment_args(
&mut self,
Expand Down
Loading