Skip to content

Commit 8513a9a

Browse files
committed
Reject escaping generic params in the type of assoc const bindings
1 parent ea0b6b0 commit 8513a9a

File tree

5 files changed

+185
-7
lines changed

5 files changed

+185
-7
lines changed

compiler/rustc_hir_analysis/messages.ftl

+14
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,20 @@ hir_analysis_only_current_traits_primitive = only traits defined in the current
285285
286286
hir_analysis_only_current_traits_ty = `{$ty}` is not defined in the current crate
287287
288+
hir_analysis_param_in_ty_of_assoc_const_binding =
289+
the type of the associated constant `{$assoc_const}` must not depend on {$synthetic ->
290+
[true] `impl Trait`
291+
*[false] generic parameters
292+
}
293+
.label = its type must not depend on {$synthetic ->
294+
[true] `impl Trait`
295+
*[false] the {$param_def_kind} `{$param_name}`
296+
}
297+
.param_defined_here_label = {$synthetic ->
298+
[true] the `impl Trait` is specified here
299+
*[false] the {$param_def_kind} `{$param_name}` is defined here
300+
}
301+
288302
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
289303
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
290304

compiler/rustc_hir_analysis/src/collect/type_of.rs

+84-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use std::ops::ControlFlow;
2+
3+
use rustc_data_structures::fx::FxIndexSet;
14
use rustc_errors::{Applicability, StashKey};
25
use rustc_hir as hir;
36
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -7,7 +10,8 @@ use rustc_middle::ty::print::with_forced_trimmed_paths;
710
use rustc_middle::ty::util::IntTypeExt;
811
use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
912
use rustc_span::symbol::Ident;
10-
use rustc_span::{Span, DUMMY_SP};
13+
use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP};
14+
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
1115

1216
use super::ItemCtxt;
1317
use super::{bad_placeholder, is_suggestable_infer_ty};
@@ -66,10 +70,23 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
6670
.expect("const parameter types cannot be generic");
6771
}
6872

69-
Node::TypeBinding(&TypeBinding { hir_id, .. }) => {
70-
// FIXME(fmease): Reject “escaping” early-bound generic parameters.
73+
Node::TypeBinding(&TypeBinding { hir_id, ident, .. }) => {
74+
let ty = tcx.type_of_assoc_const_binding(hir_id);
75+
76+
// We can't possibly catch this in the resolver, therefore we need to handle it here.
77+
// 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+
);
85+
return Ty::new_error(tcx, reported);
86+
};
87+
7188
// FIXME(fmease): Reject escaping late-bound vars.
72-
return tcx.type_of_assoc_const_binding(hir_id).skip_binder().skip_binder();
89+
return ty.skip_binder();
7390
}
7491

7592
// This match arm is for when the def_id appears in a GAT whose
@@ -282,15 +299,75 @@ pub(super) fn type_of_assoc_const_binding<'tcx>(
282299
tcx: TyCtxt<'tcx>,
283300
hir_id: HirId,
284301
) -> ty::EarlyBinder<ty::Binder<'tcx, Ty<'tcx>>> {
285-
let guar = tcx.dcx().span_delayed_bug(
286-
rustc_span::DUMMY_SP,
302+
let reported = tcx.dcx().span_delayed_bug(
303+
DUMMY_SP,
287304
format!(
288305
"attempt to obtain type of assoc const binding `{hir_id}` before \
289306
it was resolved by `add_predicates_for_ast_type_binding`"
290307
),
291308
);
292309

293-
ty::EarlyBinder::bind(ty::Binder::dummy(Ty::new_error(tcx, guar)))
310+
ty::EarlyBinder::bind(ty::Binder::dummy(Ty::new_error(tcx, reported)))
311+
}
312+
313+
fn report_overly_generic_assoc_const_binding_type<'tcx>(
314+
tcx: TyCtxt<'tcx>,
315+
assoc_const: Ident,
316+
ty: Ty<'tcx>,
317+
hir_id: HirId,
318+
) -> ErrorGuaranteed {
319+
let mut collector = GenericParamCollector { params: Default::default() };
320+
ty.visit_with(&mut collector);
321+
322+
let mut reported = None;
323+
324+
let body_owner = tcx.hir().enclosing_body_owner(hir_id);
325+
let generics = tcx.generics_of(body_owner);
326+
for (param_index, param_name) in collector.params {
327+
let param_def = generics.param_at(param_index as _, tcx);
328+
reported.get_or_insert(tcx.dcx().emit_err(crate::errors::ParamInTyOfAssocConstBinding {
329+
span: assoc_const.span,
330+
assoc_const,
331+
param_name,
332+
param_def_kind: tcx.def_descr(param_def.def_id),
333+
synthetic: param_def.kind.is_synthetic(),
334+
param_defined_here_label: tcx.def_ident_span(param_def.def_id).unwrap(),
335+
}));
336+
}
337+
338+
struct GenericParamCollector {
339+
params: FxIndexSet<(u32, Symbol)>,
340+
}
341+
342+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamCollector {
343+
type BreakTy = !;
344+
345+
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(());
349+
}
350+
ty.super_visit_with(self)
351+
}
352+
353+
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(());
357+
}
358+
ControlFlow::Continue(())
359+
}
360+
361+
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(());
365+
}
366+
ct.super_visit_with(self)
367+
}
368+
}
369+
370+
reported.unwrap_or_else(|| bug!("failed to find gen params in ty"))
294371
}
295372

296373
fn get_path_containing_arg_in_pat<'hir>(

compiler/rustc_hir_analysis/src/errors.rs

+14
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,20 @@ pub struct AssocTypeBindingNotAllowed {
254254
pub fn_trait_expansion: Option<ParenthesizedFnTraitExpansion>,
255255
}
256256

257+
#[derive(Diagnostic)]
258+
#[diag(hir_analysis_param_in_ty_of_assoc_const_binding)]
259+
pub(crate) struct ParamInTyOfAssocConstBinding {
260+
#[primary_span]
261+
#[label]
262+
pub span: Span,
263+
pub assoc_const: Ident,
264+
pub param_name: Symbol,
265+
pub param_def_kind: &'static str,
266+
pub synthetic: bool,
267+
#[label(hir_analysis_param_defined_here_label)]
268+
pub param_defined_here_label: Span,
269+
}
270+
257271
#[derive(Subdiagnostic)]
258272
#[help(hir_analysis_parenthesized_fn_trait_expansion)]
259273
pub struct ParenthesizedFnTraitExpansion {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Regression test for issue #108271.
2+
// Detect and reject generic params in the type of assoc consts used in an equality bound.
3+
#![feature(associated_const_equality)]
4+
5+
trait Trait<'a, T, const N: usize> {
6+
const K: &'a [T; N];
7+
}
8+
9+
fn take0<'r, A, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
10+
//~^ ERROR the type of the associated constant `K` must not depend on generic parameters
11+
//~| NOTE its type must not depend on the lifetime parameter `'r`
12+
//~| NOTE the lifetime parameter `'r` is defined here
13+
//~| ERROR the type of the associated constant `K` must not depend on generic parameters
14+
//~| NOTE its type must not depend on the type parameter `A`
15+
//~| NOTE the type parameter `A` is defined here
16+
//~| ERROR the type of the associated constant `K` must not depend on generic parameters
17+
//~| NOTE its type must not depend on the const parameter `Q`
18+
//~| NOTE the const parameter `Q` is defined here
19+
20+
trait Project {
21+
const SELF: Self;
22+
}
23+
24+
fn take1(_: impl Project<SELF = {}>) {}
25+
//~^ ERROR the type of the associated constant `SELF` must not depend on `impl Trait`
26+
//~| NOTE its type must not depend on `impl Trait`
27+
//~| NOTE the `impl Trait` is specified here
28+
29+
fn take2<P: Project<SELF = {}>>(_: P) {}
30+
//~^ ERROR the type of the associated constant `SELF` must not depend on generic parameters
31+
//~| NOTE its type must not depend on the type parameter `P`
32+
//~| NOTE the type parameter `P` is defined here
33+
34+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error: the type of the associated constant `K` must not depend on generic parameters
2+
--> $DIR/assoc-const-eq-param-in-ty.rs:9:57
3+
|
4+
LL | fn take0<'r, A, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
5+
| -- the lifetime parameter `'r` is defined here ^ its type must not depend on the lifetime parameter `'r`
6+
7+
error: the type of the associated constant `K` must not depend on generic parameters
8+
--> $DIR/assoc-const-eq-param-in-ty.rs:9:57
9+
|
10+
LL | fn take0<'r, A, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
11+
| - the type parameter `A` is defined here ^ its type must not depend on the type parameter `A`
12+
13+
error: the type of the associated constant `K` must not depend on generic parameters
14+
--> $DIR/assoc-const-eq-param-in-ty.rs:9:57
15+
|
16+
LL | fn take0<'r, A, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
17+
| - ^ its type must not depend on the const parameter `Q`
18+
| |
19+
| the const parameter `Q` is defined here
20+
21+
error: the type of the associated constant `SELF` must not depend on `impl Trait`
22+
--> $DIR/assoc-const-eq-param-in-ty.rs:24:26
23+
|
24+
LL | fn take1(_: impl Project<SELF = {}>) {}
25+
| -------------^^^^------
26+
| | |
27+
| | its type must not depend on `impl Trait`
28+
| the `impl Trait` is specified here
29+
30+
error: the type of the associated constant `SELF` must not depend on generic parameters
31+
--> $DIR/assoc-const-eq-param-in-ty.rs:29:21
32+
|
33+
LL | fn take2<P: Project<SELF = {}>>(_: P) {}
34+
| - ^^^^ its type must not depend on the type parameter `P`
35+
| |
36+
| the type parameter `P` is defined here
37+
38+
error: aborting due to 5 previous errors
39+

0 commit comments

Comments
 (0)