Skip to content

Commit 71373c5

Browse files
committed
GAI logic on stable too
1 parent daf5886 commit 71373c5

8 files changed

+186
-62
lines changed

compiler/rustc_hir_typeck/src/expr.rs

+1-50
Original file line numberDiff line numberDiff line change
@@ -1882,62 +1882,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18821882
// We defer checking whether the element type is `Copy` as it is possible to have
18831883
// an inference variable as a repeat count and it seems unlikely that `Copy` would
18841884
// have inference side effects required for type checking to succeed.
1885-
if tcx.features().generic_arg_infer() {
1886-
self.deferred_repeat_expr_checks.borrow_mut().push((element, element_ty, count));
1887-
// If the length is 0, we don't create any elements, so we don't copy any.
1888-
// If the length is 1, we don't copy that one element, we move it. Only check
1889-
// for `Copy` if the length is larger, or unevaluated.
1890-
} else if count.try_to_target_usize(self.tcx).is_none_or(|x| x > 1) {
1891-
self.enforce_repeat_element_needs_copy_bound(element, element_ty);
1892-
}
1885+
self.deferred_repeat_expr_checks.borrow_mut().push((element, element_ty, count));
18931886

18941887
let ty = Ty::new_array_with_const_len(tcx, t, count);
18951888
self.register_wf_obligation(ty.into(), expr.span, ObligationCauseCode::WellFormed(None));
18961889
ty
18971890
}
18981891

1899-
/// Requires that `element_ty` is `Copy` (unless it's a const expression itself).
1900-
pub(super) fn enforce_repeat_element_needs_copy_bound(
1901-
&self,
1902-
element: &hir::Expr<'_>,
1903-
element_ty: Ty<'tcx>,
1904-
) {
1905-
let tcx = self.tcx;
1906-
// Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy.
1907-
match &element.kind {
1908-
hir::ExprKind::ConstBlock(..) => return,
1909-
hir::ExprKind::Path(qpath) => {
1910-
let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
1911-
if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res
1912-
{
1913-
return;
1914-
}
1915-
}
1916-
_ => {}
1917-
}
1918-
// If someone calls a const fn or constructs a const value, they can extract that
1919-
// out into a separate constant (or a const block in the future), so we check that
1920-
// to tell them that in the diagnostic. Does not affect typeck.
1921-
let is_constable = match element.kind {
1922-
hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
1923-
ty::FnDef(def_id, _) if tcx.is_stable_const_fn(def_id) => traits::IsConstable::Fn,
1924-
_ => traits::IsConstable::No,
1925-
},
1926-
hir::ExprKind::Path(qpath) => {
1927-
match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) {
1928-
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor,
1929-
_ => traits::IsConstable::No,
1930-
}
1931-
}
1932-
_ => traits::IsConstable::No,
1933-
};
1934-
1935-
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
1936-
let code =
1937-
traits::ObligationCauseCode::RepeatElementCopy { is_constable, elt_span: element.span };
1938-
self.require_type_meets(element_ty, element.span, code, lang_item);
1939-
}
1940-
19411892
fn check_expr_tuple(
19421893
&self,
19431894
elts: &'tcx [hir::Expr<'tcx>],

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+46-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ use itertools::Itertools;
44
use rustc_data_structures::fx::FxIndexSet;
55
use rustc_errors::codes::*;
66
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, listify, pluralize};
7-
use rustc_hir::def::{CtorOf, DefKind, Res};
7+
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
88
use rustc_hir::def_id::DefId;
99
use rustc_hir::intravisit::Visitor;
10-
use rustc_hir::{ExprKind, HirId, Node, QPath};
10+
use rustc_hir::{ExprKind, HirId, LangItem, Node, QPath};
1111
use rustc_hir_analysis::check::potentially_plural_count;
1212
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
1313
use rustc_index::IndexVec;
@@ -155,6 +155,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
155155
}
156156
}
157157

158+
/// Requires that `element_ty` is `Copy` (unless it's a const expression itself).
159+
pub(super) fn enforce_repeat_element_needs_copy_bound(
160+
&self,
161+
element: &hir::Expr<'_>,
162+
element_ty: Ty<'tcx>,
163+
) {
164+
// Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy.
165+
match &element.kind {
166+
hir::ExprKind::ConstBlock(..) => return,
167+
hir::ExprKind::Path(qpath) => {
168+
let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
169+
if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res
170+
{
171+
return;
172+
}
173+
}
174+
_ => {}
175+
}
176+
177+
// If someone calls a const fn or constructs a const value, they can extract that
178+
// out into a separate constant (or a const block in the future), so we check that
179+
// to tell them that in the diagnostic. Does not affect typeck.
180+
let is_constable = match element.kind {
181+
hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
182+
ty::FnDef(def_id, _) if self.tcx.is_stable_const_fn(def_id) => {
183+
traits::IsConstable::Fn
184+
}
185+
_ => traits::IsConstable::No,
186+
},
187+
hir::ExprKind::Path(qpath) => {
188+
match self.typeck_results.borrow().qpath_res(&qpath, element.hir_id) {
189+
Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => traits::IsConstable::Ctor,
190+
_ => traits::IsConstable::No,
191+
}
192+
}
193+
_ => traits::IsConstable::No,
194+
};
195+
196+
let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
197+
let code =
198+
traits::ObligationCauseCode::RepeatElementCopy { is_constable, elt_span: element.span };
199+
self.require_type_meets(element_ty, element.span, code, lang_item);
200+
}
201+
158202
/// Generic function that factors out common logic from function calls,
159203
/// method calls and overloaded operators.
160204
pub(in super::super) fn check_argument_types(

tests/ui/lang-items/lang-item-generic-requirements.rs

+2
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@ fn ice() {
4949
// Use index
5050
let arr = [0; 5];
5151
let _ = arr[2];
52+
//~^ ERROR cannot index into a value of type `[{integer}; 5]`
5253

5354
// Use phantomdata
5455
let _ = MyPhantomData::<(), i32>;
5556

5657
// Use Foo
5758
let _: () = Foo;
59+
//~^ ERROR mismatched types
5860
}
5961

6062
// use `start`

tests/ui/lang-items/lang-item-generic-requirements.stderr

+17-3
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,23 @@ LL | r + a;
7676
| |
7777
| {integer}
7878

79+
error[E0608]: cannot index into a value of type `[{integer}; 5]`
80+
--> $DIR/lang-item-generic-requirements.rs:51:16
81+
|
82+
LL | let _ = arr[2];
83+
| ^^^
84+
85+
error[E0308]: mismatched types
86+
--> $DIR/lang-item-generic-requirements.rs:58:17
87+
|
88+
LL | let _: () = Foo;
89+
| -- ^^^ expected `()`, found `Foo`
90+
| |
91+
| expected due to this
92+
7993
error: requires `copy` lang_item
8094

81-
error: aborting due to 10 previous errors
95+
error: aborting due to 12 previous errors
8296

83-
Some errors have detailed explanations: E0369, E0392, E0718.
84-
For more information about an error, try `rustc --explain E0369`.
97+
Some errors have detailed explanations: E0308, E0369, E0392, E0608, E0718.
98+
For more information about an error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#![feature(generic_arg_infer)]
2+
3+
// Test when deferring repeat expr copy checks to end of typechecking whether elements
4+
// that are const items allow for repeat counts to go uninferred without an error being
5+
// emitted if they would later wind up inferred by integer fallback.
6+
//
7+
// This test should be updated if we wind up deferring repeat expr checks until *after*
8+
// integer fallback as the point of the test is not *specifically* about integer fallback
9+
// but rather about the behaviour of `const` element exprs.
10+
11+
trait Trait<const N: usize> {}
12+
13+
// We impl `Trait` for both `i32` and `u32` to avoid being able
14+
// to prove `?int: Trait<?n>` from there only being one impl.
15+
impl Trait<2> for i32 {}
16+
impl Trait<2> for u32 {}
17+
18+
fn tie_and_make_goal<const N: usize, T: Trait<N>>(_: &T, _: &[String; N]) {}
19+
20+
fn const_block() {
21+
// Deferred repeat expr `String; ?n`
22+
let a = [const { String::new() }; _];
23+
//~^ ERROR: type annotations needed for `[String; _]`
24+
25+
// `?int: Trait<?n>` goal
26+
tie_and_make_goal(&1, &a);
27+
28+
// If repeat expr checks structurally resolve the `?n`s before checking if the
29+
// element is a `const` then we would error here. Otherwise we avoid doing so,
30+
// integer fallback occurs, allowing `?int: Trait<?n>` goals to make progress,
31+
// inferring the repeat counts (to `2` but that doesn't matter as the element is `const`).
32+
}
33+
34+
fn const_item() {
35+
const MY_CONST: String = String::new();
36+
37+
// Deferred repeat expr `String; ?n`
38+
let a = [MY_CONST; _];
39+
//~^ ERROR: type annotations needed for `[String; _]`
40+
41+
// `?int: Trait<?n>` goal
42+
tie_and_make_goal(&1, &a);
43+
44+
// ... same as `const_block`
45+
}
46+
47+
fn assoc_const() {
48+
trait Dummy {
49+
const ASSOC: String;
50+
}
51+
impl Dummy for () {
52+
const ASSOC: String = String::new();
53+
}
54+
55+
// Deferred repeat expr `String; ?n`
56+
let a = [<() as Dummy>::ASSOC; _];
57+
//~^ ERROR: type annotations needed for `[String; _]`
58+
59+
// `?int: Trait<?n>` goal
60+
tie_and_make_goal(&1, &a);
61+
62+
// ... same as `const_block`
63+
}
64+
65+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
error[E0282]: type annotations needed for `[String; _]`
2+
--> $DIR/copy-check-const-element-uninferred-count.rs:22:9
3+
|
4+
LL | let a = [const { String::new() }; _];
5+
| ^ ----------------------- type must be known at this point
6+
|
7+
help: consider giving `a` an explicit type, where the value of const parameter `N` is specified
8+
|
9+
LL | let a: [_; N] = [const { String::new() }; _];
10+
| ++++++++
11+
12+
error[E0282]: type annotations needed for `[String; _]`
13+
--> $DIR/copy-check-const-element-uninferred-count.rs:38:9
14+
|
15+
LL | let a = [MY_CONST; _];
16+
| ^ -------- type must be known at this point
17+
|
18+
help: consider giving `a` an explicit type, where the value of const parameter `N` is specified
19+
|
20+
LL | let a: [_; N] = [MY_CONST; _];
21+
| ++++++++
22+
23+
error[E0282]: type annotations needed for `[String; _]`
24+
--> $DIR/copy-check-const-element-uninferred-count.rs:56:9
25+
|
26+
LL | let a = [<() as Dummy>::ASSOC; _];
27+
| ^ -------------------- type must be known at this point
28+
|
29+
help: consider giving `a` an explicit type, where the value of const parameter `N` is specified
30+
|
31+
LL | let a: [_; N] = [<() as Dummy>::ASSOC; _];
32+
| ++++++++
33+
34+
error: aborting due to 3 previous errors
35+
36+
For more information about this error, try `rustc --explain E0282`.

tests/ui/repeat-expr/copy-inference-side-effects-are-lazy.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
//@revisions: current gai
2-
//@[current] check-pass
3-
4-
#![cfg_attr(gai, feature(generic_arg_infer))]
5-
61
use std::marker::PhantomData;
72

83
struct Foo<T>(PhantomData<T>);
@@ -20,6 +15,6 @@ fn extract<T, const N: usize>(_: [Foo<T>; N]) -> T {
2015

2116
fn main() {
2217
let x = [Foo(PhantomData); 2];
23-
//[gai]~^ ERROR: type annotations needed
24-
_ = extract(x).max(2);
18+
//~^ ERROR: type annotations needed
19+
extract(x).max(2);
2520
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0282]: type annotations needed for `[Foo<_>; 2]`
2+
--> $DIR/copy-inference-side-effects-are-lazy.rs:17:9
3+
|
4+
LL | let x = [Foo(PhantomData); 2];
5+
| ^
6+
LL |
7+
LL | extract(x).max(2);
8+
| ---------- type must be known at this point
9+
|
10+
help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
11+
|
12+
LL | let x: [Foo<T>; 2] = [Foo(PhantomData); 2];
13+
| +++++++++++++
14+
15+
error: aborting due to 1 previous error
16+
17+
For more information about this error, try `rustc --explain E0282`.

0 commit comments

Comments
 (0)