Skip to content

Commit 8d1b59a

Browse files
committed
Reject 'escaping' gen params in the ty of assoc consts in eq bounds
1 parent 4c0addc commit 8d1b59a

File tree

5 files changed

+175
-2
lines changed

5 files changed

+175
-2
lines changed

compiler/rustc_hir_analysis/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ hir_analysis_only_current_traits_primitive = only traits defined in the current
265265
266266
hir_analysis_only_current_traits_ty = `{$ty}` is not defined in the current crate
267267
268+
hir_analysis_param_in_ty_of_assoc_const = the type of the associated constant `{$assoc_const}` must not depend on generic parameters
269+
.label = its type must not depend on the {$param_kind} parameter `{$param_name}`
270+
.param_defined_here_label = the {$param_kind} parameter `{$param_name}` is defined here
271+
268272
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
269273
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
270274

compiler/rustc_hir_analysis/src/collect/type_of.rs

+82-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::ops::ControlFlow;
2+
13
use rustc_errors::{Applicability, StashKey};
24
use rustc_hir as hir;
35
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -7,8 +9,9 @@ use rustc_middle::ty::print::with_forced_trimmed_paths;
79
use rustc_middle::ty::util::IntTypeExt;
810
use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
911
use rustc_span::symbol::Ident;
10-
use rustc_span::{Span, DUMMY_SP};
12+
use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP};
1113
use rustc_trait_selection::traits;
14+
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
1215

1316
use super::{bad_placeholder, is_suggestable_infer_ty};
1417
use super::{AstConv, ItemCtxt};
@@ -88,6 +91,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
8891
// FIXME(associated_const_equality): This isn't correct, it should be the concrete /
8992
// instantiated self type. Theoretically, we could search for it in the HIR of the
9093
// parent item but that's super fragile and hairy.
94+
// If the projected type ends up containing this `Self` parameter, we will reject it
95+
// below, so not much harm done.
9196
Some(tcx.types.self_param),
9297
ty::BoundConstness::NotConst,
9398
);
@@ -132,7 +137,16 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
132137
parent_args,
133138
);
134139

135-
return tcx.type_of(assoc_item.def_id).instantiate(tcx, args);
140+
let ty = tcx.type_of(assoc_item.def_id).instantiate(tcx, args);
141+
142+
// FIXME(const_generics): Support generic const generics.
143+
if ty.has_param() {
144+
// We can't possibly catch this in the resolver, therefore we need to handle it here.
145+
let reported = report_unsupported_generic_associated_const(tcx, ident, ty, hir_id);
146+
return Ty::new_error(tcx, reported);
147+
}
148+
149+
return ty;
136150
}
137151

138152
// This match arm is for when the def_id appears in a GAT whose
@@ -340,6 +354,72 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
340354
}
341355
}
342356

357+
fn report_unsupported_generic_associated_const<'tcx>(
358+
tcx: TyCtxt<'tcx>,
359+
assoc_const: Ident,
360+
ty: Ty<'tcx>,
361+
hir_id: HirId,
362+
) -> ErrorGuaranteed {
363+
// Just find the first generic parameter. This should be sufficient in practice.
364+
let ControlFlow::Break((param_index, param_name)) = ty.visit_with(&mut GenericParamFinder)
365+
else {
366+
bug!()
367+
};
368+
369+
// FIXME(associated_const_equality): Since we use a `Self` type parameter as a hack in
370+
// `anon_const_type_of`, we can't be sure where `Self` comes from: It may come from the
371+
// def site or the usage site of the assoc const. Therefore, don't try to find its definition.
372+
let (param_kind, param_def_span) = if param_name != rustc_span::symbol::kw::SelfUpper {
373+
let body_owner = tcx.hir().enclosing_body_owner(hir_id);
374+
let param_def = tcx.generics_of(body_owner).param_at(param_index as _, tcx);
375+
(&param_def.kind, Some(tcx.def_ident_span(param_def.def_id).unwrap()))
376+
} else {
377+
(&ty::GenericParamDefKind::Type { has_default: false, synthetic: false }, None)
378+
};
379+
380+
struct GenericParamFinder;
381+
382+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamFinder {
383+
type BreakTy = (u32, Symbol);
384+
385+
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
386+
if let ty::Param(param) = ty.kind() {
387+
return ControlFlow::Break((param.index, param.name));
388+
}
389+
390+
ty.super_visit_with(self)
391+
}
392+
393+
fn visit_region(&mut self, re: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
394+
if let ty::ReEarlyParam(param) = re.kind() {
395+
return ControlFlow::Break((param.index, param.name));
396+
}
397+
398+
ControlFlow::Continue(())
399+
}
400+
401+
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
402+
if let ty::ConstKind::Param(param) = ct.kind() {
403+
return ControlFlow::Break((param.index, param.name));
404+
}
405+
406+
ct.super_visit_with(self)
407+
}
408+
}
409+
410+
tcx.sess.emit_err(crate::errors::ParamInTyOfAssocConst {
411+
span: assoc_const.span,
412+
assoc_const,
413+
param_name,
414+
param_kind: match param_kind {
415+
ty::GenericParamDefKind::Lifetime => "lifetime",
416+
ty::GenericParamDefKind::Type { .. } => "type",
417+
ty::GenericParamDefKind::Const { .. } => "const",
418+
},
419+
param_defined_here_label: param_def_span,
420+
})
421+
}
422+
343423
fn get_path_containing_arg_in_pat<'hir>(
344424
pat: &'hir hir::Pat<'hir>,
345425
arg_id: HirId,

compiler/rustc_hir_analysis/src/errors.rs

+13
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,19 @@ pub struct AssocTypeBindingNotAllowed {
142142
pub fn_trait_expansion: Option<ParenthesizedFnTraitExpansion>,
143143
}
144144

145+
#[derive(Diagnostic)]
146+
#[diag(hir_analysis_param_in_ty_of_assoc_const)]
147+
pub(crate) struct ParamInTyOfAssocConst {
148+
#[primary_span]
149+
#[label]
150+
pub span: Span,
151+
pub assoc_const: Ident,
152+
pub param_name: Symbol,
153+
pub param_kind: &'static str,
154+
#[label(hir_analysis_param_defined_here_label)]
155+
pub param_defined_here_label: Option<Span>,
156+
}
157+
145158
#[derive(Subdiagnostic)]
146159
#[help(hir_analysis_parenthesized_fn_trait_expansion)]
147160
pub struct ParenthesizedFnTraitExpansion {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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>(_: impl Trait<'r, (), 0, K = { &[] }>) {}
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+
fn take1<A>(_: impl Trait<'static, A, 0, K = { &[] }>) {}
14+
//~^ ERROR the type of the associated constant `K` must not depend on generic parameters
15+
//~| NOTE its type must not depend on the type parameter `A`
16+
//~| NOTE the type parameter `A` is defined here
17+
fn take2<const Q: usize>(_: impl Trait<'static, (), Q, K = { [] }>) {}
18+
//~^ ERROR the type of the associated constant `K` must not depend on generic parameters
19+
//~| NOTE its type must not depend on the const parameter `Q`
20+
//~| NOTE the const parameter `Q` is defined here
21+
22+
trait Project {
23+
const S: Self;
24+
}
25+
26+
// FIXME(associated_const_equality): The error messages below aren't super great at the moment:
27+
// Here, `Self` is a type parameter of the trait `Project`, not of the function `take3`
28+
// unlike the cases above. We should mention the APIT / the parameter `P` instead.
29+
30+
fn take3(_: impl Project<S = {}>) {}
31+
//~^ ERROR the type of the associated constant `S` must not depend on generic parameters
32+
//~| NOTE its type must not depend on the type parameter `Self`
33+
34+
fn take4<P: Project<S = {}>>(_: P) {}
35+
//~^ ERROR the type of the associated constant `S` must not depend on generic parameters
36+
//~| NOTE its type must not depend on the type parameter `Self`
37+
38+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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:39
3+
|
4+
LL | fn take0<'r>(_: impl Trait<'r, (), 0, K = { &[] }>) {}
5+
| -- ^ its type must not depend on the lifetime parameter `'r`
6+
| |
7+
| the lifetime parameter `'r` is defined here
8+
9+
error: the type of the associated constant `K` must not depend on generic parameters
10+
--> $DIR/assoc-const-eq-param-in-ty.rs:13:42
11+
|
12+
LL | fn take1<A>(_: impl Trait<'static, A, 0, K = { &[] }>) {}
13+
| - ^ its type must not depend on the type parameter `A`
14+
| |
15+
| the type parameter `A` is defined here
16+
17+
error: the type of the associated constant `K` must not depend on generic parameters
18+
--> $DIR/assoc-const-eq-param-in-ty.rs:17:56
19+
|
20+
LL | fn take2<const Q: usize>(_: impl Trait<'static, (), Q, K = { [] }>) {}
21+
| - ^ its type must not depend on the const parameter `Q`
22+
| |
23+
| the const parameter `Q` is defined here
24+
25+
error: the type of the associated constant `S` must not depend on generic parameters
26+
--> $DIR/assoc-const-eq-param-in-ty.rs:30:26
27+
|
28+
LL | fn take3(_: impl Project<S = {}>) {}
29+
| ^ its type must not depend on the type parameter `Self`
30+
31+
error: the type of the associated constant `S` must not depend on generic parameters
32+
--> $DIR/assoc-const-eq-param-in-ty.rs:34:21
33+
|
34+
LL | fn take4<P: Project<S = {}>>(_: P) {}
35+
| ^ its type must not depend on the type parameter `Self`
36+
37+
error: aborting due to 5 previous errors
38+

0 commit comments

Comments
 (0)