Skip to content

Commit 3a8cacb

Browse files
authored
Rollup merge of rust-lang#123130 - oli-obk:missing_type_taint, r=compiler-errors
Load missing type of impl associated constant from trait definition fixes rust-lang#123092 Also does some cleanups I discovered while analyzing this issue
2 parents 8427c80 + 86e750f commit 3a8cacb

File tree

6 files changed

+132
-66
lines changed

6 files changed

+132
-66
lines changed

compiler/rustc_hir_typeck/src/lib.rs

+57-53
Original file line numberDiff line numberDiff line change
@@ -83,20 +83,6 @@ macro_rules! type_error_struct {
8383
})
8484
}
8585

86-
/// If this `DefId` is a "primary tables entry", returns
87-
/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
88-
///
89-
/// If this function returns `Some`, then `typeck_results(def_id)` will
90-
/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
91-
/// may not succeed. In some cases where this function returns `None`
92-
/// (notably closures), `typeck_results(def_id)` would wind up
93-
/// redirecting to the owning function.
94-
fn primary_body_of(
95-
node: Node<'_>,
96-
) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
97-
Some((node.body_id()?, node.ty(), node.fn_sig()))
98-
}
99-
10086
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
10187
// Closures' typeck results come from their outermost function,
10288
// as they are part of the same "inference environment".
@@ -106,7 +92,7 @@ fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
10692
}
10793

10894
if let Some(def_id) = def_id.as_local() {
109-
primary_body_of(tcx.hir_node_by_def_id(def_id)).is_some()
95+
tcx.hir_node_by_def_id(def_id).body_id().is_some()
11096
} else {
11197
false
11298
}
@@ -163,7 +149,7 @@ fn typeck_with_fallback<'tcx>(
163149
let span = tcx.hir().span(id);
164150

165151
// Figure out what primary body this item has.
166-
let (body_id, body_ty, fn_sig) = primary_body_of(node).unwrap_or_else(|| {
152+
let body_id = node.body_id().unwrap_or_else(|| {
167153
span_bug!(span, "can't type-check body of {:?}", def_id);
168154
});
169155
let body = tcx.hir().body(body_id);
@@ -176,7 +162,7 @@ fn typeck_with_fallback<'tcx>(
176162
}
177163
let mut fcx = FnCtxt::new(&root_ctxt, param_env, def_id);
178164

179-
if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
165+
if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() {
180166
let fn_sig = if decl.output.get_infer_ret_ty().is_some() {
181167
fcx.lowerer().lower_fn_ty(id, header.unsafety, header.abi, decl, None, None)
182168
} else {
@@ -191,42 +177,7 @@ fn typeck_with_fallback<'tcx>(
191177

192178
check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params);
193179
} else {
194-
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = body_ty {
195-
Some(fcx.next_ty_var(TypeVariableOrigin {
196-
kind: TypeVariableOriginKind::TypeInference,
197-
span,
198-
}))
199-
} else if let Node::AnonConst(_) = node {
200-
match tcx.parent_hir_node(id) {
201-
Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), .. })
202-
if anon_const.hir_id == id =>
203-
{
204-
Some(fcx.next_ty_var(TypeVariableOrigin {
205-
kind: TypeVariableOriginKind::TypeInference,
206-
span,
207-
}))
208-
}
209-
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), .. })
210-
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), .. }) => {
211-
asm.operands.iter().find_map(|(op, _op_sp)| match op {
212-
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => {
213-
// Inline assembly constants must be integers.
214-
Some(fcx.next_int_var())
215-
}
216-
hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => {
217-
Some(fcx.next_ty_var(TypeVariableOrigin {
218-
kind: TypeVariableOriginKind::MiscVariable,
219-
span,
220-
}))
221-
}
222-
_ => None,
223-
})
224-
}
225-
_ => None,
226-
}
227-
} else {
228-
None
229-
};
180+
let expected_type = infer_type_if_missing(&fcx, node);
230181
let expected_type = expected_type.unwrap_or_else(fallback);
231182

232183
let expected_type = fcx.normalize(body.value.span, expected_type);
@@ -296,6 +247,59 @@ fn typeck_with_fallback<'tcx>(
296247
typeck_results
297248
}
298249

250+
fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Option<Ty<'tcx>> {
251+
let tcx = fcx.tcx;
252+
let def_id = fcx.body_id;
253+
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = node.ty() {
254+
if let Some(item) = tcx.opt_associated_item(def_id.into())
255+
&& let ty::AssocKind::Const = item.kind
256+
&& let ty::ImplContainer = item.container
257+
&& let Some(trait_item) = item.trait_item_def_id
258+
{
259+
let args =
260+
tcx.impl_trait_ref(item.container_id(tcx)).unwrap().instantiate_identity().args;
261+
Some(tcx.type_of(trait_item).instantiate(tcx, args))
262+
} else {
263+
Some(fcx.next_ty_var(TypeVariableOrigin {
264+
kind: TypeVariableOriginKind::TypeInference,
265+
span,
266+
}))
267+
}
268+
} else if let Node::AnonConst(_) = node {
269+
let id = tcx.local_def_id_to_hir_id(def_id);
270+
match tcx.parent_hir_node(id) {
271+
Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), span, .. })
272+
if anon_const.hir_id == id =>
273+
{
274+
Some(fcx.next_ty_var(TypeVariableOrigin {
275+
kind: TypeVariableOriginKind::TypeInference,
276+
span,
277+
}))
278+
}
279+
Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. })
280+
| Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => {
281+
asm.operands.iter().find_map(|(op, _op_sp)| match op {
282+
hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => {
283+
// Inline assembly constants must be integers.
284+
Some(fcx.next_int_var())
285+
}
286+
hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => {
287+
Some(fcx.next_ty_var(TypeVariableOrigin {
288+
kind: TypeVariableOriginKind::MiscVariable,
289+
span,
290+
}))
291+
}
292+
_ => None,
293+
})
294+
}
295+
_ => None,
296+
}
297+
} else {
298+
None
299+
};
300+
expected_type
301+
}
302+
299303
/// When `check_fn` is invoked on a coroutine (i.e., a body that
300304
/// includes yield), it returns back some information about the yield
301305
/// points.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//! Test that we compute the right type for associated constants
2+
//! of impls, even if the type is missing. We know it from the trait
3+
//! declaration after all.
4+
5+
trait Range {
6+
const FIRST: u8;
7+
const LAST: u8;
8+
}
9+
10+
struct TwoDigits;
11+
impl Range for TwoDigits {
12+
const FIRST: = 10;
13+
//~^ ERROR: missing type for `const` item
14+
const LAST: u8 = 99;
15+
}
16+
17+
const fn digits(x: u8) -> usize {
18+
match x {
19+
TwoDigits::FIRST..=TwoDigits::LAST => 0,
20+
0..=9 | 100..=255 => panic!(),
21+
}
22+
}
23+
24+
const FOOMP: [(); {
25+
digits(42)
26+
}] = [];
27+
28+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: missing type for `const` item
2+
--> $DIR/missing_assoc_const_type.rs:12:17
3+
|
4+
LL | const FIRST: = 10;
5+
| ^ help: provide a type for the associated constant: `u8`
6+
7+
error: aborting due to 1 previous error
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//! Test that we compute the right type for associated constants
2+
//! of impls, even if the type is missing. We know it from the trait
3+
//! declaration after all.
4+
5+
trait Range {
6+
const FIRST: u8;
7+
const LAST: u8;
8+
}
9+
10+
struct TwoDigits;
11+
impl Range for TwoDigits {
12+
const FIRST: = 10;
13+
//~^ ERROR: missing type
14+
const LAST: u8 = 99;
15+
}
16+
17+
const FOOMP: [(); {
18+
TwoDigits::FIRST as usize
19+
}] = [(); 10];
20+
21+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: missing type for `const` item
2+
--> $DIR/missing_assoc_const_type2.rs:12:17
3+
|
4+
LL | const FIRST: = 10;
5+
| ^ help: provide a type for the associated constant: `u8`
6+
7+
error: aborting due to 1 previous error
8+

tests/ui/typeck/typeck_type_placeholder_item.stderr

+10-13
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,15 @@ help: use type parameters instead
546546
LL | fn fn_test10<T>(&self, _x : T) { }
547547
| +++ ~
548548

549+
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
550+
--> $DIR/typeck_type_placeholder_item.rs:194:14
551+
|
552+
LL | const D: _ = 42;
553+
| ^
554+
| |
555+
| not allowed in type signatures
556+
| help: replace with the correct type: `i32`
557+
549558
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
550559
--> $DIR/typeck_type_placeholder_item.rs:217:31
551560
|
@@ -574,19 +583,7 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures
574583
--> $DIR/typeck_type_placeholder_item.rs:209:14
575584
|
576585
LL | const D: _ = 42;
577-
| ^
578-
| |
579-
| not allowed in type signatures
580-
| help: replace with the correct type: `i32`
581-
582-
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
583-
--> $DIR/typeck_type_placeholder_item.rs:194:14
584-
|
585-
LL | const D: _ = 42;
586-
| ^
587-
| |
588-
| not allowed in type signatures
589-
| help: replace with the correct type: `i32`
586+
| ^ not allowed in type signatures
590587

591588
error[E0046]: not all trait items implemented, missing: `F`
592589
--> $DIR/typeck_type_placeholder_item.rs:200:1

0 commit comments

Comments
 (0)