Skip to content

Commit a3b31a1

Browse files
committed
Reject escaping bound vars in the type of assoc const bindings
1 parent 8513a9a commit a3b31a1

File tree

5 files changed

+132
-27
lines changed

5 files changed

+132
-27
lines changed

compiler/rustc_hir_analysis/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ hir_analysis_enum_discriminant_overflowed = enum discriminant overflowed
122122
.label = overflowed on value after {$discr}
123123
.note = explicitly set `{$item_name} = {$wrapped_discr}` if that is desired outcome
124124
125+
hir_analysis_escaping_bound_var_in_ty_of_assoc_const_binding =
126+
the type of the associated constant `{$assoc_const}` cannot capture late-bound generic parameters
127+
.label = its type cannot capture the late-bound {$var_def_kind} `{$var_name}`
128+
.var_defined_here_label = the late-bound {$var_def_kind} `{$var_name}` is defined here
129+
125130
hir_analysis_field_already_declared =
126131
field `{$field_name}` is already declared
127132
.label = field already declared

compiler/rustc_hir_analysis/src/collect/type_of.rs

+90-27
Original file line numberDiff line numberDiff line change
@@ -71,22 +71,17 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
7171
}
7272

7373
Node::TypeBinding(&TypeBinding { hir_id, ident, .. }) => {
74-
let ty = tcx.type_of_assoc_const_binding(hir_id);
74+
let ty = tcx.type_of_assoc_const_binding(hir_id).skip_binder().skip_binder();
7575

7676
// We can't possibly catch this in the resolver, therefore we need to handle it here.
7777
// FIXME(const_generics): Support generic const generics.
78-
let Some(ty) = ty.no_bound_vars() else {
79-
let reported = report_overly_generic_assoc_const_binding_type(
80-
tcx,
81-
ident,
82-
ty.skip_binder().skip_binder(),
83-
hir_id,
84-
);
78+
if ty.has_param() || ty.has_escaping_bound_vars() {
79+
let reported =
80+
report_overly_generic_assoc_const_binding_type(tcx, ident, ty, hir_id);
8581
return Ty::new_error(tcx, reported);
8682
};
8783

88-
// FIXME(fmease): Reject escaping late-bound vars.
89-
return ty.skip_binder();
84+
return ty;
9085
}
9186

9287
// This match arm is for when the def_id appears in a GAT whose
@@ -316,8 +311,15 @@ fn report_overly_generic_assoc_const_binding_type<'tcx>(
316311
ty: Ty<'tcx>,
317312
hir_id: HirId,
318313
) -> ErrorGuaranteed {
319-
let mut collector = GenericParamCollector { params: Default::default() };
320-
ty.visit_with(&mut collector);
314+
let mut collector = GenericParamAndBoundVarCollector {
315+
tcx,
316+
params: Default::default(),
317+
vars: Default::default(),
318+
depth: ty::INNERMOST,
319+
};
320+
if let ControlFlow::Break(reported) = ty.visit_with(&mut collector) {
321+
return reported;
322+
}
321323

322324
let mut reported = None;
323325

@@ -334,40 +336,101 @@ fn report_overly_generic_assoc_const_binding_type<'tcx>(
334336
param_defined_here_label: tcx.def_ident_span(param_def.def_id).unwrap(),
335337
}));
336338
}
339+
for (var_def_id, var_name) in collector.vars {
340+
reported.get_or_insert(tcx.dcx().emit_err(
341+
crate::errors::EscapingBoundVarInTyOfAssocConstBinding {
342+
span: assoc_const.span,
343+
assoc_const,
344+
var_name,
345+
var_def_kind: tcx.def_descr(var_def_id),
346+
var_defined_here_label: tcx.def_ident_span(var_def_id).unwrap(),
347+
},
348+
));
349+
}
337350

338-
struct GenericParamCollector {
351+
struct GenericParamAndBoundVarCollector<'tcx> {
352+
tcx: TyCtxt<'tcx>,
339353
params: FxIndexSet<(u32, Symbol)>,
354+
vars: FxIndexSet<(DefId, Symbol)>,
355+
depth: ty::DebruijnIndex,
340356
}
341357

342-
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamCollector {
343-
type BreakTy = !;
358+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'tcx> {
359+
type BreakTy = ErrorGuaranteed;
360+
361+
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
362+
&mut self,
363+
binder: &ty::Binder<'tcx, T>,
364+
) -> ControlFlow<Self::BreakTy> {
365+
self.depth.shift_in(1);
366+
let binder = binder.super_visit_with(self);
367+
self.depth.shift_out(1);
368+
binder
369+
}
344370

345371
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
346-
if let ty::Param(param) = ty.kind() {
347-
self.params.insert((param.index, param.name));
348-
return ControlFlow::Continue(());
372+
match ty.kind() {
373+
ty::Param(param) => {
374+
self.params.insert((param.index, param.name));
375+
}
376+
ty::Bound(db, bt) if *db >= self.depth => {
377+
self.vars.insert(match bt.kind {
378+
ty::BoundTyKind::Param(def_id, name) => (def_id, name),
379+
ty::BoundTyKind::Anon => {
380+
let reported = self.tcx.dcx().span_delayed_bug(
381+
DUMMY_SP,
382+
format!("unexpected anon bound ty: {:?}", bt.var),
383+
);
384+
return ControlFlow::Break(reported);
385+
}
386+
});
387+
}
388+
_ => return ty.super_visit_with(self),
349389
}
350-
ty.super_visit_with(self)
390+
ControlFlow::Continue(())
351391
}
352392

353393
fn visit_region(&mut self, re: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
354-
if let ty::ReEarlyParam(param) = re.kind() {
355-
self.params.insert((param.index, param.name));
356-
return ControlFlow::Continue(());
394+
match re.kind() {
395+
ty::ReEarlyParam(param) => {
396+
self.params.insert((param.index, param.name));
397+
}
398+
ty::ReBound(db, br) if db >= self.depth => {
399+
self.vars.insert(match br.kind {
400+
ty::BrNamed(def_id, name) => (def_id, name),
401+
ty::BrAnon | ty::BrEnv => {
402+
let reported = self.tcx.dcx().span_delayed_bug(
403+
DUMMY_SP,
404+
format!("unexpected bound region kind: {:?}", br.kind),
405+
);
406+
return ControlFlow::Break(reported);
407+
}
408+
});
409+
}
410+
_ => {}
357411
}
358412
ControlFlow::Continue(())
359413
}
360414

361415
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
362-
if let ty::ConstKind::Param(param) = ct.kind() {
363-
self.params.insert((param.index, param.name));
364-
return ControlFlow::Continue(());
416+
match ct.kind() {
417+
ty::ConstKind::Param(param) => {
418+
self.params.insert((param.index, param.name));
419+
ControlFlow::Continue(())
420+
}
421+
ty::ConstKind::Bound(db, ty::BoundVar { .. }) if db >= self.depth => {
422+
let reported = self.tcx.dcx().span_delayed_bug(
423+
DUMMY_SP,
424+
"late-bound const params are not supported yet",
425+
);
426+
ControlFlow::Break(reported)
427+
}
428+
_ => ct.super_visit_with(self),
365429
}
366-
ct.super_visit_with(self)
367430
}
368431
}
369432

370-
reported.unwrap_or_else(|| bug!("failed to find gen params in ty"))
433+
reported.unwrap_or_else(|| bug!("failed to find gen params or bound vars in ty"))
371434
}
372435

373436
fn get_path_containing_arg_in_pat<'hir>(

compiler/rustc_hir_analysis/src/errors.rs

+13
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,19 @@ pub(crate) struct ParamInTyOfAssocConstBinding {
268268
pub param_defined_here_label: Span,
269269
}
270270

271+
#[derive(Diagnostic)]
272+
#[diag(hir_analysis_escaping_bound_var_in_ty_of_assoc_const_binding)]
273+
pub(crate) struct EscapingBoundVarInTyOfAssocConstBinding {
274+
#[primary_span]
275+
#[label]
276+
pub span: Span,
277+
pub assoc_const: Ident,
278+
pub var_name: Symbol,
279+
pub var_def_kind: &'static str,
280+
#[label(hir_analysis_var_defined_here_label)]
281+
pub var_defined_here_label: Span,
282+
}
283+
271284
#[derive(Subdiagnostic)]
272285
#[help(hir_analysis_parenthesized_fn_trait_expansion)]
273286
pub struct ParenthesizedFnTraitExpansion {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Detect and reject escaping late-bound generic params in
2+
// the type of assoc consts used in an equality bound.
3+
#![feature(associated_const_equality)]
4+
5+
trait Trait<'a> {
6+
const K: &'a ();
7+
}
8+
9+
fn take(_: impl for<'r> Trait<'r, K = { &() }>) {}
10+
//~^ ERROR the type of the associated constant `K` cannot capture late-bound generic parameters
11+
//~| NOTE its type cannot capture the late-bound lifetime parameter `'r`
12+
//~| NOTE the late-bound lifetime parameter `'r` is defined here
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: the type of the associated constant `K` cannot capture late-bound generic parameters
2+
--> $DIR/assoc-const-eq-esc-bound-var-in-ty.rs:9:35
3+
|
4+
LL | fn take(_: impl for<'r> Trait<'r, K = { &() }>) {}
5+
| -- ^ its type cannot capture the late-bound lifetime parameter `'r`
6+
| |
7+
| the late-bound lifetime parameter `'r` is defined here
8+
9+
error: aborting due to 1 previous error
10+

0 commit comments

Comments
 (0)