Skip to content

Commit ae258e1

Browse files
committed
Auto merge of rust-lang#135272 - BoxyUwU:generic_arg_infer_reliability_2, r=<try>
Forbid usage of `hir` `Infer` const/ty variants in ambiguous contexts The feature `generic_arg_infer` allows providing `_` as an argument to const generics in order to infer them. This introduces a syntactic ambiguity as to whether generic arguments are type or const arguments. In order to get around this we introduced a fourth `GenericArg` variant, `Infer` used to represent `_` as an argument to generic parameters when we don't know if its a type or a const argument. This made hir visitors that care about `TyKind::Infer` or `ConstArgKind::Infer` very error prone as checking for `TyKind::Infer`s in `visit_ty` would find *some* type infer arguments but not *all* of them as they would sometimes be lowered to `GenericArg::Infer` instead. Additionally the `visit_infer` method would previously only visit `GenericArg::Infer` not *all* infers (e.g. `TyKind::Infer`), this made it very easy to override `visit_infer` and expect it to visit all infers when in reality it would only visit *some* infers. --- This PR aims to fix those issues by making the `TyKind` and `ConstArgKind` types generic over whether the infer types/consts are represented by `Ty/ConstArgKind::Infer` or out of line (e.g. by a `GenericArg::Infer` or accessible by overiding `visit_infer`). We then make HIR Visitors convert all const args and types to the versions where infer vars are stored out of line and call `visit_infer` in cases where a `Ty`/`Const` would previously have had a `Ty/ConstArgKind::Infer` variant: API Summary ```rust enum AmbigArg {} enum Ty/ConstArgKind<Unambig = ()> { ... Infer(Unambig), } impl Ty/ConstArg { fn try_as_ambig_ty/ct(self) -> Option<Ty/ConstArg<AmbigArg>>; } impl Ty/ConstArg<AmbigArg> { fn as_unambig_ty/ct(self) -> Ty/ConstArg; } enum InferKind { Ty(Ty), Const(ConstArg), Ambig(InferArg), } trait Visitor { ... fn visit_ty/const_arg(&mut self, Ty/ConstArg<AmbigArg>) -> Self::Result; fn visit_infer(&mut self, id: HirId, sp: Span, kind: InferKind) -> Self::Result; } // blanket impl'd, not meant to be overriden trait VisitorExt { fn visit_ty/const_arg_unambig(&mut self, Ty/ConstArg) -> Self::Result; } fn walk_unambig_ty/const_arg(&mut V, Ty/ConstArg) -> Self::Result; fn walk_ty/const_arg(&mut V, Ty/ConstArg<AmbigArg>) -> Self::Result; ``` The end result is that `visit_infer` visits *all* infer args and is also the *only* way to visit an infer arg, `visit_ty` and `visit_const_arg` can now no longer encounter a `Ty/ConstArgKind::Infer`. Representing this in the type system means that it is now very difficult to mess things up, either accessing `TyKind::Infer` "just works" and you won't miss *some* type infers- or it doesn't work and you have to look at `visit_infer` or some `GenericArg::Infer` which forces you to think about the full complexity involved. Unfortunately there is no lint right now about explicitly matching on uninhabited variants, I can't find the context for why this is the case 🤷‍♀️ I'm not convinced the framing of un/ambig ty/consts is necessarily the right one but I'm not sure what would be better. I somewhat like calling them full/partial types based on the fact that `Ty<Partial>`/`Ty<Full>` directly specifies how many of the type kinds are actually represented compared to `Ty<Ambig>` which which leaves that to the reader to figure out based on the logical consequences of it the type being in an ambiguous position. --- tool changes have been modified in their own commits for easier reviewing by anyone getting cc'd from subtree changes. I also attempted to split out "bug fixes arising from the refactoring" into their own commit so they arent lumped in with a big general refactor commit Fixes rust-lang#112110
2 parents 01706e1 + d7b916b commit ae258e1

File tree

118 files changed

+1023
-662
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

118 files changed

+1023
-662
lines changed

compiler/rustc_ast/src/ast.rs

+26-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use rustc_data_structures::packed::Pu128;
2828
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
2929
use rustc_data_structures::stack::ensure_sufficient_stack;
3030
use rustc_data_structures::sync::Lrc;
31+
use rustc_data_structures::tagged_ptr::Tag;
3132
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
3233
pub use rustc_span::AttrId;
3334
use rustc_span::source_map::{Spanned, respan};
@@ -2269,10 +2270,32 @@ impl TyKind {
22692270

22702271
/// Syntax used to declare a trait object.
22712272
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
2273+
#[repr(u8)]
22722274
pub enum TraitObjectSyntax {
2273-
Dyn,
2274-
DynStar,
2275-
None,
2275+
// SAFETY: When adding new variants make sure to update the `Tag` impl.
2276+
Dyn = 0,
2277+
DynStar = 1,
2278+
None = 2,
2279+
}
2280+
2281+
/// SAFETY: `TraitObjectSyntax` only has 3 data-less variants which means
2282+
/// it can be represented with a `u2`. We use `repr(u8)` to guarantee the
2283+
/// discriminants of the variants are no greater than `3`.
2284+
unsafe impl Tag for TraitObjectSyntax {
2285+
const BITS: u32 = 2;
2286+
2287+
fn into_usize(self) -> usize {
2288+
self as u8 as usize
2289+
}
2290+
2291+
unsafe fn from_usize(tag: usize) -> Self {
2292+
match tag {
2293+
0 => TraitObjectSyntax::Dyn,
2294+
1 => TraitObjectSyntax::DynStar,
2295+
2 => TraitObjectSyntax::None,
2296+
_ => unreachable!(),
2297+
}
2298+
}
22762299
}
22772300

22782301
#[derive(Clone, Encodable, Decodable, Debug)]

compiler/rustc_ast_lowering/src/index.rs

+26-14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use intravisit::InferKind;
12
use rustc_data_structures::sorted_map::SortedMap;
23
use rustc_hir as hir;
34
use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
@@ -258,14 +259,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
258259
});
259260
}
260261

261-
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir>) {
262-
self.insert(const_arg.span(), const_arg.hir_id, Node::ConstArg(const_arg));
263-
264-
self.with_parent(const_arg.hir_id, |this| {
265-
intravisit::walk_const_arg(this, const_arg);
266-
});
267-
}
268-
269262
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
270263
self.insert(expr.span, expr.hir_id, Node::Expr(expr));
271264

@@ -295,22 +288,41 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
295288
intravisit::walk_path_segment(self, path_segment);
296289
}
297290

298-
fn visit_ty(&mut self, ty: &'hir Ty<'hir>) {
299-
self.insert(ty.span, ty.hir_id, Node::Ty(ty));
291+
fn visit_ty(&mut self, ty: &'hir Ty<'hir, AmbigArg>) {
292+
self.insert(ty.span, ty.hir_id, Node::Ty(ty.as_unambig_ty()));
300293

301294
self.with_parent(ty.hir_id, |this| {
302295
intravisit::walk_ty(this, ty);
303296
});
304297
}
305298

306-
fn visit_infer(&mut self, inf: &'hir InferArg) {
307-
self.insert(inf.span, inf.hir_id, Node::Infer(inf));
299+
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) {
300+
self.insert(
301+
const_arg.as_unambig_ct().span(),
302+
const_arg.hir_id,
303+
Node::ConstArg(const_arg.as_unambig_ct()),
304+
);
308305

309-
self.with_parent(inf.hir_id, |this| {
310-
intravisit::walk_inf(this, inf);
306+
self.with_parent(const_arg.hir_id, |this| {
307+
intravisit::walk_ambig_const_arg(this, const_arg);
311308
});
312309
}
313310

311+
fn visit_infer(
312+
&mut self,
313+
inf_id: HirId,
314+
inf_span: Span,
315+
kind: InferKind<'hir>,
316+
) -> Self::Result {
317+
match kind {
318+
InferKind::Ty(ty) => self.insert(inf_span, inf_id, Node::Ty(ty)),
319+
InferKind::Const(ct) => self.insert(inf_span, inf_id, Node::ConstArg(ct)),
320+
InferKind::Ambig(inf) => self.insert(inf_span, inf_id, Node::Infer(inf)),
321+
}
322+
323+
self.visit_id(inf_id);
324+
}
325+
314326
fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
315327
self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));
316328

compiler/rustc_ast_lowering/src/lib.rs

+15-10
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
4848
use rustc_data_structures::sorted_map::SortedMap;
4949
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
5050
use rustc_data_structures::sync::Lrc;
51+
use rustc_data_structures::tagged_ptr::TaggedRef;
5152
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
5253
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
5354
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
@@ -1084,7 +1085,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10841085
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
10851086
ast::GenericArg::Type(ty) => {
10861087
match &ty.kind {
1087-
TyKind::Infer if self.tcx.features().generic_arg_infer() => {
1088+
TyKind::Infer => {
10881089
return GenericArg::Infer(hir::InferArg {
10891090
hir_id: self.lower_node_id(ty.id),
10901091
span: self.lower_span(ty.span),
@@ -1110,15 +1111,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11101111

11111112
let ct =
11121113
self.lower_const_path_to_const_arg(path, res, ty.id, ty.span);
1113-
return GenericArg::Const(ct);
1114+
return GenericArg::Const(ct.try_as_ambig_ct().unwrap());
11141115
}
11151116
}
11161117
}
11171118
_ => {}
11181119
}
1119-
GenericArg::Type(self.lower_ty(ty, itctx))
1120+
GenericArg::Type(self.lower_ty(ty, itctx).try_as_ambig_ty().unwrap())
1121+
}
1122+
ast::GenericArg::Const(ct) => {
1123+
GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap())
11201124
}
1121-
ast::GenericArg::Const(ct) => GenericArg::Const(self.lower_anon_const_to_const_arg(ct)),
11221125
}
11231126
}
11241127

@@ -1158,7 +1161,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11581161
let lifetime_bound = this.elided_dyn_bound(t.span);
11591162
(bounds, lifetime_bound)
11601163
});
1161-
let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
1164+
let kind = hir::TyKind::TraitObject(
1165+
bounds,
1166+
TaggedRef::new(lifetime_bound, TraitObjectSyntax::None),
1167+
);
11621168
return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
11631169
}
11641170

@@ -1185,7 +1191,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11851191

11861192
fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
11871193
let kind = match &t.kind {
1188-
TyKind::Infer => hir::TyKind::Infer,
1194+
TyKind::Infer => hir::TyKind::Infer(()),
11891195
TyKind::Err(guar) => hir::TyKind::Err(*guar),
11901196
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
11911197
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
@@ -1309,7 +1315,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13091315
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
13101316
(bounds, lifetime_bound)
13111317
});
1312-
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
1318+
hir::TyKind::TraitObject(bounds, TaggedRef::new(lifetime_bound, *kind))
13131319
}
13141320
TyKind::ImplTrait(def_node_id, bounds) => {
13151321
let span = t.span;
@@ -2041,7 +2047,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20412047
)
20422048
.stash(c.value.span, StashKey::UnderscoreForArrayLengths);
20432049
}
2044-
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span));
2050+
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ());
20452051
self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
20462052
}
20472053
_ => self.lower_anon_const_to_const_arg(c),
@@ -2365,8 +2371,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23652371
hir_id = self.next_id();
23662372
hir::TyKind::TraitObject(
23672373
arena_vec![self; principal],
2368-
self.elided_dyn_bound(span),
2369-
TraitObjectSyntax::None,
2374+
TaggedRef::new(self.elided_dyn_bound(span), TraitObjectSyntax::None),
23702375
)
23712376
}
23722377
_ => hir::TyKind::Path(hir::QPath::Resolved(None, path)),

compiler/rustc_ast_lowering/src/path.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
525525
}
526526
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
527527
};
528-
let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
528+
let args = smallvec![GenericArg::Type(
529+
self.arena.alloc(self.ty_tup(*inputs_span, inputs)).try_as_ambig_ty().unwrap()
530+
)];
529531

530532
// If we have a bound like `async Fn() -> T`, make sure that we mark the
531533
// `Output = T` associated type bound with the right feature gates.

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_hir::QPath::Resolved;
88
use rustc_hir::WherePredicateKind::BoundPredicate;
99
use rustc_hir::def::Res::Def;
1010
use rustc_hir::def_id::DefId;
11-
use rustc_hir::intravisit::Visitor;
11+
use rustc_hir::intravisit::VisitorExt;
1212
use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
1313
use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
1414
use rustc_middle::bug;
@@ -887,7 +887,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
887887
if alias_ty.span.desugaring_kind().is_some() {
888888
// Skip `async` desugaring `impl Future`.
889889
}
890-
if let TyKind::TraitObject(_, lt, _) = alias_ty.kind {
890+
if let TyKind::TraitObject(_, lt) = alias_ty.kind {
891891
if lt.ident.name == kw::Empty {
892892
spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
893893
} else {
@@ -987,7 +987,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
987987
for found_did in found_dids {
988988
let mut traits = vec![];
989989
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
990-
hir_v.visit_ty(self_ty);
990+
hir_v.visit_ty_unambig(self_ty);
991991
debug!("trait spans found: {:?}", traits);
992992
for span in &traits {
993993
let mut multi_span: MultiSpan = vec![*span].into();

compiler/rustc_borrowck/src/diagnostics/region_name.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
432432
// must highlight the variable.
433433
// NOTE(eddyb) this is handled in/by the sole caller
434434
// (`give_name_if_anonymous_region_appears_in_arguments`).
435-
hir::TyKind::Infer => None,
435+
hir::TyKind::Infer(()) => None,
436436

437437
_ => Some(argument_hir_ty),
438438
}
@@ -615,7 +615,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
615615
}
616616

617617
(GenericArgKind::Type(ty), hir::GenericArg::Type(hir_ty)) => {
618-
search_stack.push((ty, hir_ty));
618+
search_stack.push((ty, hir_ty.as_unambig_ty()));
619619
}
620620

621621
(GenericArgKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => {

0 commit comments

Comments
 (0)