Skip to content

Commit e6d7ab2

Browse files
authored
Rollup merge of rust-lang#133831 - BoxyUwU:ice_on_unfed_type_of, r=compiler-errors
Don't try and handle unfed `type_of` on anon consts The `type_of` query for anon consts in the type system is actually implemented by feeding the return value during hir ty lowering, not the hir-based logic in `const_arg_anon_type_of`. The HIR based logic is incomplete (doesn't handle all hir nodes) and also generally wrong to call (re-lowers HIR or invokes typeck which can result in query cycles). r? `@compiler-errors`
2 parents 4b2d68d + 52d1c30 commit e6d7ab2

File tree

7 files changed

+16
-271
lines changed

7 files changed

+16
-271
lines changed

compiler/rustc_hir_analysis/src/collect.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -309,10 +309,10 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
309309
self.tcx.ensure().type_of(param.def_id);
310310
if let Some(default) = default {
311311
// need to store default and type of default
312+
self.tcx.ensure().const_param_default(param.def_id);
312313
if let hir::ConstArgKind::Anon(ac) = default.kind {
313314
self.tcx.ensure().type_of(ac.def_id);
314315
}
315-
self.tcx.ensure().const_param_default(param.def_id);
316316
}
317317
}
318318
}
@@ -1817,7 +1817,6 @@ fn const_param_default<'tcx>(
18171817
),
18181818
};
18191819
let icx = ItemCtxt::new(tcx, def_id);
1820-
// FIXME(const_generics): investigate which places do and don't need const ty feeding
1821-
let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::No);
1820+
let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id()));
18221821
ty::EarlyBinder::bind(ct)
18231822
}

compiler/rustc_hir_analysis/src/collect/type_of.rs

+8-235
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableEx
1212
use rustc_middle::{bug, span_bug};
1313
use rustc_span::symbol::Ident;
1414
use rustc_span::{DUMMY_SP, Span};
15-
use tracing::debug;
1615

1716
use super::{ItemCtxt, bad_placeholder};
1817
use crate::errors::TypeofReservedKeywordUsed;
@@ -138,252 +137,26 @@ fn const_arg_anon_type_of<'tcx>(tcx: TyCtxt<'tcx>, arg_hir_id: HirId, span: Span
138137
use hir::*;
139138
use rustc_middle::ty::Ty;
140139

141-
let parent_node_id = tcx.parent_hir_id(arg_hir_id);
142-
let parent_node = tcx.hir_node(parent_node_id);
143-
144-
let (generics, arg_idx) = match parent_node {
145-
// Easy case: arrays repeat expressions.
140+
match tcx.parent_hir_node(arg_hir_id) {
141+
// Array length const arguments do not have `type_of` fed as there is never a corresponding
142+
// generic parameter definition.
146143
Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. })
147144
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
148145
if constant.hir_id == arg_hir_id =>
149146
{
150147
return tcx.types.usize;
151148
}
152-
Node::GenericParam(&GenericParam {
153-
def_id: param_def_id,
154-
kind: GenericParamKind::Const { default: Some(ct), .. },
155-
..
156-
}) if ct.hir_id == arg_hir_id => {
157-
return tcx
158-
.type_of(param_def_id)
159-
.no_bound_vars()
160-
.expect("const parameter types cannot be generic");
161-
}
162-
163-
// This match arm is for when the def_id appears in a GAT whose
164-
// path can't be resolved without typechecking e.g.
165-
//
166-
// trait Foo {
167-
// type Assoc<const N: usize>;
168-
// fn foo() -> Self::Assoc<3>;
169-
// }
170-
//
171-
// In the above code we would call this query with the def_id of 3 and
172-
// the parent_node we match on would be the hir node for Self::Assoc<3>
173-
//
174-
// `Self::Assoc<3>` cant be resolved without typechecking here as we
175-
// didnt write <Self as Foo>::Assoc<3>. If we did then another match
176-
// arm would handle this.
177-
//
178-
// I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
179-
Node::Ty(hir_ty @ hir::Ty { kind: TyKind::Path(QPath::TypeRelative(ty, segment)), .. }) => {
180-
// Find the Item containing the associated type so we can create an ItemCtxt.
181-
// Using the ItemCtxt lower the HIR for the unresolved assoc type into a
182-
// ty which is a fully resolved projection.
183-
// For the code example above, this would mean lowering `Self::Assoc<3>`
184-
// to a ty::Alias(ty::Projection, `<Self as Foo>::Assoc<3>`).
185-
let item_def_id = tcx.hir().get_parent_item(ty.hir_id).def_id;
186-
let ty = ItemCtxt::new(tcx, item_def_id).lower_ty(hir_ty);
187-
188-
// Iterate through the generics of the projection to find the one that corresponds to
189-
// the def_id that this query was called with. We filter to only type and const args here
190-
// as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
191-
// but it can't hurt to be safe ^^
192-
if let ty::Alias(ty::Projection | ty::Inherent, projection) = ty.kind() {
193-
let generics = tcx.generics_of(projection.def_id);
194-
195-
let arg_index = segment
196-
.args
197-
.and_then(|args| {
198-
args.args
199-
.iter()
200-
.filter(|arg| arg.is_ty_or_const())
201-
.position(|arg| arg.hir_id() == arg_hir_id)
202-
})
203-
.unwrap_or_else(|| {
204-
bug!("no arg matching AnonConst in segment");
205-
});
206-
207-
(generics, arg_index)
208-
} else {
209-
// I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
210-
return Ty::new_error_with_message(
211-
tcx,
212-
span,
213-
"unexpected non-GAT usage of an anon const",
214-
);
215-
}
216-
}
217-
Node::Expr(&Expr {
218-
kind:
219-
ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
220-
..
221-
}) => {
222-
let body_owner = tcx.hir().enclosing_body_owner(arg_hir_id);
223-
let tables = tcx.typeck(body_owner);
224-
// This may fail in case the method/path does not actually exist.
225-
// As there is no relevant param for `def_id`, we simply return
226-
// `None` here.
227-
let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else {
228-
return Ty::new_error_with_message(
229-
tcx,
230-
span,
231-
format!("unable to find type-dependent def for {parent_node_id:?}"),
232-
);
233-
};
234-
let idx = segment
235-
.args
236-
.and_then(|args| {
237-
args.args
238-
.iter()
239-
.filter(|arg| arg.is_ty_or_const())
240-
.position(|arg| arg.hir_id() == arg_hir_id)
241-
})
242-
.unwrap_or_else(|| {
243-
bug!("no arg matching ConstArg in segment");
244-
});
245-
246-
(tcx.generics_of(type_dependent_def), idx)
247-
}
248-
249-
Node::Ty(&hir::Ty { kind: TyKind::Path(_), .. })
250-
| Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
251-
| Node::TraitRef(..)
252-
| Node::Pat(_) => {
253-
let path = match parent_node {
254-
Node::Ty(&hir::Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
255-
| Node::TraitRef(&TraitRef { path, .. }) => &*path,
256-
Node::Expr(&Expr {
257-
kind:
258-
ExprKind::Path(QPath::Resolved(_, path))
259-
| ExprKind::Struct(&QPath::Resolved(_, path), ..),
260-
..
261-
}) => {
262-
let body_owner = tcx.hir().enclosing_body_owner(arg_hir_id);
263-
let _tables = tcx.typeck(body_owner);
264-
&*path
265-
}
266-
Node::Pat(pat) => {
267-
if let Some(path) = get_path_containing_arg_in_pat(pat, arg_hir_id) {
268-
path
269-
} else {
270-
return Ty::new_error_with_message(
271-
tcx,
272-
span,
273-
format!("unable to find const parent for {arg_hir_id} in pat {pat:?}"),
274-
);
275-
}
276-
}
277-
_ => {
278-
return Ty::new_error_with_message(
279-
tcx,
280-
span,
281-
format!("unexpected const parent path {parent_node:?}"),
282-
);
283-
}
284-
};
285-
286-
// We've encountered an `AnonConst` in some path, so we need to
287-
// figure out which generic parameter it corresponds to and return
288-
// the relevant type.
289-
let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| {
290-
let args = seg.args?;
291-
args.args
292-
.iter()
293-
.filter(|arg| arg.is_ty_or_const())
294-
.position(|arg| arg.hir_id() == arg_hir_id)
295-
.map(|index| (index, seg))
296-
.or_else(|| {
297-
args.constraints
298-
.iter()
299-
.copied()
300-
.filter_map(AssocItemConstraint::ct)
301-
.position(|ct| ct.hir_id == arg_hir_id)
302-
.map(|idx| (idx, seg))
303-
})
304-
}) else {
305-
return Ty::new_error_with_message(tcx, span, "no arg matching AnonConst in path");
306-
};
307-
308-
let generics = match tcx.res_generics_def_id(segment.res) {
309-
Some(def_id) => tcx.generics_of(def_id),
310-
None => {
311-
return Ty::new_error_with_message(
312-
tcx,
313-
span,
314-
format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
315-
);
316-
}
317-
};
318-
319-
(generics, arg_index)
320-
}
321149

322-
_ => {
323-
return Ty::new_error_with_message(
324-
tcx,
325-
span,
326-
format!("unexpected const arg parent in type_of(): {parent_node:?}"),
327-
);
328-
}
329-
};
330-
331-
debug!(?parent_node);
332-
debug!(?generics, ?arg_idx);
333-
if let Some(param_def_id) = generics
334-
.own_params
335-
.iter()
336-
.filter(|param| param.kind.is_ty_or_const())
337-
.nth(match generics.has_self && generics.parent.is_none() {
338-
true => arg_idx + 1,
339-
false => arg_idx,
340-
})
341-
.and_then(|param| match param.kind {
342-
ty::GenericParamDefKind::Const { .. } => {
343-
debug!(?param);
344-
Some(param.def_id)
345-
}
346-
_ => None,
347-
})
348-
{
349-
tcx.type_of(param_def_id).no_bound_vars().expect("const parameter types cannot be generic")
350-
} else {
351-
return Ty::new_error_with_message(
150+
// This is not a `bug!` as const arguments in path segments that did not resolve to anything
151+
// will result in `type_of` never being fed.
152+
_ => Ty::new_error_with_message(
352153
tcx,
353154
span,
354-
format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"),
355-
);
155+
"`type_of` called on const argument's anon const before the const argument was lowered",
156+
),
356157
}
357158
}
358159

359-
fn get_path_containing_arg_in_pat<'hir>(
360-
pat: &'hir hir::Pat<'hir>,
361-
arg_id: HirId,
362-
) -> Option<&'hir hir::Path<'hir>> {
363-
use hir::*;
364-
365-
let is_arg_in_path = |p: &hir::Path<'_>| {
366-
p.segments
367-
.iter()
368-
.filter_map(|seg| seg.args)
369-
.flat_map(|args| args.args)
370-
.any(|arg| arg.hir_id() == arg_id)
371-
};
372-
let mut arg_path = None;
373-
pat.walk(|pat| match pat.kind {
374-
PatKind::Struct(QPath::Resolved(_, path), _, _)
375-
| PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
376-
| PatKind::Path(QPath::Resolved(_, path))
377-
if is_arg_in_path(path) =>
378-
{
379-
arg_path = Some(path);
380-
false
381-
}
382-
_ => true,
383-
});
384-
arg_path
385-
}
386-
387160
pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> {
388161
use rustc_hir::*;
389162
use rustc_middle::ty::Ty;

tests/ui/const-generics/issues/cg-in-dyn-issue-128176.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//@ check-pass
22

3-
// Regression test for #128176.
3+
// Regression test for #128176. Previously we would call `type_of` on the `1` anon const
4+
// before the anon const had been lowered and had the `type_of` fed with a result.
45

56
#![feature(generic_const_exprs)]
67
#![feature(dyn_compatible_for_dispatch)]

tests/ui/coroutine/coroutine-in-orphaned-anon-const.rs

-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
trait X {
44
fn test() -> Self::Assoc<{ async {} }>;
55
//~^ ERROR associated type `Assoc` not found for `Self`
6-
//~| ERROR associated type `Assoc` not found for `Self`
7-
86
}
97

108
pub fn main() {}

tests/ui/coroutine/coroutine-in-orphaned-anon-const.stderr

+1-9
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,6 @@ error[E0220]: associated type `Assoc` not found for `Self`
44
LL | fn test() -> Self::Assoc<{ async {} }>;
55
| ^^^^^ associated type `Assoc` not found
66

7-
error[E0220]: associated type `Assoc` not found for `Self`
8-
--> $DIR/coroutine-in-orphaned-anon-const.rs:4:24
9-
|
10-
LL | fn test() -> Self::Assoc<{ async {} }>;
11-
| ^^^^^ associated type `Assoc` not found
12-
|
13-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
14-
15-
error: aborting due to 2 previous errors
7+
error: aborting due to 1 previous error
168

179
For more information about this error, try `rustc --explain E0220`.

tests/ui/traits/bound/unknown-assoc-with-const-arg.rs

-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
trait X {
44
fn a<T>() -> T::unknown<{}> {}
55
//~^ ERROR: associated type `unknown` not found for `T`
6-
//~| ERROR: associated type `unknown` not found for `T`
76
}
87

98
trait Y {
@@ -14,7 +13,6 @@ trait Y {
1413
trait Z<T> {
1514
fn a() -> T::unknown<{}> {}
1615
//~^ ERROR: associated type `unknown` not found for `T`
17-
//~| ERROR: associated type `unknown` not found for `T`
1816
}
1917

2018
fn main() {}

tests/ui/traits/bound/unknown-assoc-with-const-arg.stderr

+3-19
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,18 @@ LL | fn a<T>() -> T::unknown<{}> {}
55
| ^^^^^^^ associated type `unknown` not found
66

77
error[E0220]: associated type `unknown` not found for `T`
8-
--> $DIR/unknown-assoc-with-const-arg.rs:15:18
8+
--> $DIR/unknown-assoc-with-const-arg.rs:14:18
99
|
1010
LL | fn a() -> T::unknown<{}> {}
1111
| ^^^^^^^ associated type `unknown` not found
1212

13-
error[E0220]: associated type `unknown` not found for `T`
14-
--> $DIR/unknown-assoc-with-const-arg.rs:4:21
15-
|
16-
LL | fn a<T>() -> T::unknown<{}> {}
17-
| ^^^^^^^ associated type `unknown` not found
18-
|
19-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
20-
21-
error[E0220]: associated type `unknown` not found for `T`
22-
--> $DIR/unknown-assoc-with-const-arg.rs:15:18
23-
|
24-
LL | fn a() -> T::unknown<{}> {}
25-
| ^^^^^^^ associated type `unknown` not found
26-
|
27-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
28-
2913
error[E0433]: failed to resolve: use of undeclared type `NOT_EXIST`
30-
--> $DIR/unknown-assoc-with-const-arg.rs:10:15
14+
--> $DIR/unknown-assoc-with-const-arg.rs:9:15
3115
|
3216
LL | fn a() -> NOT_EXIST::unknown<{}> {}
3317
| ^^^^^^^^^ use of undeclared type `NOT_EXIST`
3418

35-
error: aborting due to 5 previous errors
19+
error: aborting due to 3 previous errors
3620

3721
Some errors have detailed explanations: E0220, E0433.
3822
For more information about an error, try `rustc --explain E0220`.

0 commit comments

Comments
 (0)