Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8231e85

Browse files
committed
Auto merge of #135272 - BoxyUwU:generic_arg_infer_reliability_2, r=compiler-errors
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 #112110
2 parents 061ee95 + c58fe21 commit 8231e85

File tree

119 files changed

+1054
-667
lines changed

Some content is hidden

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

119 files changed

+1054
-667
lines changed

‎compiler/rustc_ast/src/ast.rs

Lines changed: 35 additions & 3 deletions
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};
@@ -287,6 +288,7 @@ impl ParenthesizedArgs {
287288
}
288289
}
289290

291+
use crate::AstDeref;
290292
pub use crate::node_id::{CRATE_NODE_ID, DUMMY_NODE_ID, NodeId};
291293

292294
/// Modifiers on a trait bound like `~const`, `?` and `!`.
@@ -2165,6 +2167,14 @@ impl Ty {
21652167
}
21662168
final_ty
21672169
}
2170+
2171+
pub fn is_maybe_parenthesised_infer(&self) -> bool {
2172+
match &self.kind {
2173+
TyKind::Infer => true,
2174+
TyKind::Paren(inner) => inner.ast_deref().is_maybe_parenthesised_infer(),
2175+
_ => false,
2176+
}
2177+
}
21682178
}
21692179

21702180
#[derive(Clone, Encodable, Decodable, Debug)]
@@ -2269,10 +2279,32 @@ impl TyKind {
22692279

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

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

‎compiler/rustc_ast_lowering/src/index.rs

Lines changed: 26 additions & 14 deletions
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};
@@ -265,14 +266,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
265266
});
266267
}
267268

268-
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir>) {
269-
self.insert(const_arg.span(), const_arg.hir_id, Node::ConstArg(const_arg));
270-
271-
self.with_parent(const_arg.hir_id, |this| {
272-
intravisit::walk_const_arg(this, const_arg);
273-
});
274-
}
275-
276269
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
277270
self.insert(expr.span, expr.hir_id, Node::Expr(expr));
278271

@@ -302,22 +295,41 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
302295
intravisit::walk_path_segment(self, path_segment);
303296
}
304297

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

308301
self.with_parent(ty.hir_id, |this| {
309302
intravisit::walk_ty(this, ty);
310303
});
311304
}
312305

313-
fn visit_infer(&mut self, inf: &'hir InferArg) {
314-
self.insert(inf.span, inf.hir_id, Node::Infer(inf));
306+
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) {
307+
self.insert(
308+
const_arg.as_unambig_ct().span(),
309+
const_arg.hir_id,
310+
Node::ConstArg(const_arg.as_unambig_ct()),
311+
);
315312

316-
self.with_parent(inf.hir_id, |this| {
317-
intravisit::walk_inf(this, inf);
313+
self.with_parent(const_arg.hir_id, |this| {
314+
intravisit::walk_ambig_const_arg(this, const_arg);
318315
});
319316
}
320317

318+
fn visit_infer(
319+
&mut self,
320+
inf_id: HirId,
321+
inf_span: Span,
322+
kind: InferKind<'hir>,
323+
) -> Self::Result {
324+
match kind {
325+
InferKind::Ty(ty) => self.insert(inf_span, inf_id, Node::Ty(ty)),
326+
InferKind::Const(ct) => self.insert(inf_span, inf_id, Node::ConstArg(ct)),
327+
InferKind::Ambig(inf) => self.insert(inf_span, inf_id, Node::Infer(inf)),
328+
}
329+
330+
self.visit_id(inf_id);
331+
}
332+
321333
fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
322334
self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));
323335

‎compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 25 additions & 15 deletions
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};
@@ -1083,17 +1084,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10831084
match arg {
10841085
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)),
10851086
ast::GenericArg::Type(ty) => {
1087+
// We cannot just match on `TyKind::Infer` as `(_)` is represented as
1088+
// `TyKind::Paren(TyKind::Infer)` and should also be lowered to `GenericArg::Infer`
1089+
if ty.is_maybe_parenthesised_infer() {
1090+
return GenericArg::Infer(hir::InferArg {
1091+
hir_id: self.lower_node_id(ty.id),
1092+
span: self.lower_span(ty.span),
1093+
});
1094+
}
1095+
10861096
match &ty.kind {
1087-
TyKind::Infer if self.tcx.features().generic_arg_infer() => {
1088-
return GenericArg::Infer(hir::InferArg {
1089-
hir_id: self.lower_node_id(ty.id),
1090-
span: self.lower_span(ty.span),
1091-
});
1092-
}
10931097
// We parse const arguments as path types as we cannot distinguish them during
10941098
// parsing. We try to resolve that ambiguity by attempting resolution in both the
10951099
// type and value namespaces. If we resolved the path in the value namespace, we
10961100
// transform it into a generic const argument.
1101+
//
1102+
// FIXME: Should we be handling `(PATH_TO_CONST)`?
10971103
TyKind::Path(None, path) => {
10981104
if let Some(res) = self
10991105
.resolver
@@ -1110,15 +1116,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11101116

11111117
let ct =
11121118
self.lower_const_path_to_const_arg(path, res, ty.id, ty.span);
1113-
return GenericArg::Const(ct);
1119+
return GenericArg::Const(ct.try_as_ambig_ct().unwrap());
11141120
}
11151121
}
11161122
}
11171123
_ => {}
11181124
}
1119-
GenericArg::Type(self.lower_ty(ty, itctx))
1125+
GenericArg::Type(self.lower_ty(ty, itctx).try_as_ambig_ty().unwrap())
1126+
}
1127+
ast::GenericArg::Const(ct) => {
1128+
GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap())
11201129
}
1121-
ast::GenericArg::Const(ct) => GenericArg::Const(self.lower_anon_const_to_const_arg(ct)),
11221130
}
11231131
}
11241132

@@ -1158,7 +1166,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11581166
let lifetime_bound = this.elided_dyn_bound(t.span);
11591167
(bounds, lifetime_bound)
11601168
});
1161-
let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
1169+
let kind = hir::TyKind::TraitObject(
1170+
bounds,
1171+
TaggedRef::new(lifetime_bound, TraitObjectSyntax::None),
1172+
);
11621173
return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
11631174
}
11641175

@@ -1185,7 +1196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11851196

11861197
fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
11871198
let kind = match &t.kind {
1188-
TyKind::Infer => hir::TyKind::Infer,
1199+
TyKind::Infer => hir::TyKind::Infer(()),
11891200
TyKind::Err(guar) => hir::TyKind::Err(*guar),
11901201
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
11911202
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
@@ -1309,7 +1320,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13091320
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
13101321
(bounds, lifetime_bound)
13111322
});
1312-
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
1323+
hir::TyKind::TraitObject(bounds, TaggedRef::new(lifetime_bound, *kind))
13131324
}
13141325
TyKind::ImplTrait(def_node_id, bounds) => {
13151326
let span = t.span;
@@ -2041,7 +2052,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20412052
)
20422053
.stash(c.value.span, StashKey::UnderscoreForArrayLengths);
20432054
}
2044-
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span));
2055+
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span),());
20452056
self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
20462057
}
20472058
_ => self.lower_anon_const_to_const_arg(c),
@@ -2365,8 +2376,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
23652376
hir_id = self.next_id();
23662377
hir::TyKind::TraitObject(
23672378
arena_vec![self; principal],
2368-
self.elided_dyn_bound(span),
2369-
TraitObjectSyntax::None,
2379+
TaggedRef::new(self.elided_dyn_bound(span), TraitObjectSyntax::None),
23702380
)
23712381
}
23722382
_ => hir::TyKind::Path(hir::QPath::Resolved(None, path)),

‎compiler/rustc_ast_lowering/src/path.rs

Lines changed: 3 additions & 1 deletion
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

Lines changed: 3 additions & 3 deletions
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

Lines changed: 2 additions & 2 deletions
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)

AltStyle によって変換されたページ (->オリジナル) /