Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_resolve/src/diagnostics/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
suggestion,
current,
type_span,
type_name,
} => {
// let foo =...
// ^^^ given this Span
Expand Down Expand Up @@ -1216,6 +1217,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
suggestion,
current,
type_span,
type_name,
}),
Some(diagnostics::AttemptToUseNonConstantValueInConstantLabelWithSuggestion { span }),
None,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_resolve/src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,9 @@ pub(crate) struct AttemptToUseNonConstantValueInConstantWithSuggestion<'a> {
#[suggestion_part(code = "{suggestion} ")]
pub(crate) span: Span,
pub(crate) suggestion: &'a str,
#[suggestion_part(code = ": /* Type */")]
#[suggestion_part(code = ": {type_name}")]
pub(crate) type_span: Option<Span>,
pub(crate) type_name: &'a str,
pub(crate) current: &'a str,
}

Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1511,7 +1511,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
res_err = Some((span, CannotCaptureDynamicEnvironmentInFnItem));
}
}
RibKind::ConstantItem(_, item) => {
RibKind::ConstantItem(_, item, type_suggestion) => {
// Still doesn't deal with upvars
if let Some(span) = finalize {
let (span, resolution_error) = match item {
Expand Down Expand Up @@ -1540,6 +1540,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
suggestion: "const",
current: "let",
type_span,
type_name: type_suggestion.as_str(),
},
)
}
Expand All @@ -1550,6 +1551,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
suggestion: "let",
current: kind.as_str(),
type_span: None,
type_name: type_suggestion.as_str(),
},
),
};
Expand Down Expand Up @@ -1610,7 +1612,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}

RibKind::ConstantItem(trivial, _) => {
RibKind::ConstantItem(trivial, _, _) => {
if let ConstantHasGenerics::No(cause) = trivial
&& !matches!(res, Res::SelfTyAlias { .. })
{
Expand Down Expand Up @@ -1704,7 +1706,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}

RibKind::ConstantItem(trivial, _) => {
RibKind::ConstantItem(trivial, _, _) => {
if let ConstantHasGenerics::No(cause) = trivial {
if let Some(span) = finalize {
let error = match cause {
Expand Down
93 changes: 71 additions & 22 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,30 @@ enum AnonConstKind {
EnumDiscriminant,
FieldDefaultValue,
InlineConst,
/// Array type length, e.g. `[T; N]`.
ArrayLength,
ConstArg(IsRepeatExpr),
}

/// Type ascription to suggest when turning a `let` binding into a `const`
/// because it was used in a constant context without an existing type annotation.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum NonConstantTypeSuggestion {
/// Suggest `: /* Type */`.
Placeholder,
/// Suggest `: usize` (array lengths and repeat counts).
Usize,
}

impl NonConstantTypeSuggestion {
pub(crate) fn as_str(self) -> &'static str {
match self {
Self::Placeholder => "/* Type */",
Self::Usize => "usize",
}
}
}

impl PatternSource {
fn descr(self) -> &'static str {
match self {
Expand Down Expand Up @@ -214,7 +235,10 @@ pub(crate) enum RibKind<'ra> {
///
/// The item may reference generic parameters in trivial constant expressions.
/// All other constants aren't allowed to use generic params at all.
ConstantItem(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>),
///
/// The third field is used when suggesting that a `let` binding used in this
/// constant context should become a `const`, to pick a sensible type ascription.
ConstantItem(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>, NonConstantTypeSuggestion),

/// We passed through a module item.
Module(LocalModule<'ra>),
Expand Down Expand Up @@ -1038,7 +1062,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc
}
TyKind::Array(element_ty, length) => {
self.visit_ty(element_ty);
self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No));
self.resolve_anon_const(length, AnonConstKind::ArrayLength);
}
_ => visit::walk_ty(self, ty),
}
Expand Down Expand Up @@ -3021,6 +3045,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
IsRepeatExpr::No,
ConstantHasGenerics::Yes,
Some((ConstBlockItem::IDENT, ConstantItemKind::Const)),
NonConstantTypeSuggestion::Placeholder,
|this| this.resolve_labeled_block(None, block.id, block),
)
},
Expand Down Expand Up @@ -3295,21 +3320,30 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
is_repeat: IsRepeatExpr,
may_use_generics: ConstantHasGenerics,
item: Option<(Ident, ConstantItemKind)>,
type_suggestion: NonConstantTypeSuggestion,
f: impl FnOnce(&mut Self),
) {
let f = |this: &mut Self| {
this.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item), |this| {
this.with_rib(
TypeNS,
RibKind::ConstantItem(
may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
item,
),
|this| {
this.with_label_rib(RibKind::ConstantItem(may_use_generics, item), f);
},
)
})
this.with_rib(
ValueNS,
RibKind::ConstantItem(may_use_generics, item, type_suggestion),
|this| {
this.with_rib(
TypeNS,
RibKind::ConstantItem(
may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
item,
type_suggestion,
),
|this| {
this.with_label_rib(
RibKind::ConstantItem(may_use_generics, item, type_suggestion),
f,
);
},
)
},
)
};

if let ConstantHasGenerics::No(cause) = may_use_generics {
Expand Down Expand Up @@ -3864,9 +3898,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {

fn resolve_static_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) {
self.with_lifetime_rib(LifetimeRibKind::elided(LifetimeRes::Infer), |this| {
this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| {
this.visit_expr(expr)
});
this.with_constant_rib(
IsRepeatExpr::No,
ConstantHasGenerics::Yes,
item,
NonConstantTypeSuggestion::Placeholder,
|this| this.visit_expr(expr),
);
})
}

Expand All @@ -3877,9 +3915,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
) {
if let Some(body) = body {
self.with_lifetime_rib(LifetimeRibKind::elided(LifetimeRes::Infer), |this| {
this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| {
this.visit_expr(body)
})
this.with_constant_rib(
IsRepeatExpr::No,
ConstantHasGenerics::Yes,
item,
NonConstantTypeSuggestion::Placeholder,
|this| this.visit_expr(body),
)
})
}
}
Expand Down Expand Up @@ -5152,13 +5194,20 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
_ => IsRepeatExpr::No,
};

let type_suggestion = match anon_const_kind {
AnonConstKind::ArrayLength | AnonConstKind::ConstArg(IsRepeatExpr::Yes) => {
NonConstantTypeSuggestion::Usize
}
_ => NonConstantTypeSuggestion::Placeholder,
};

let may_use_generics = match anon_const_kind {
AnonConstKind::EnumDiscriminant => {
ConstantHasGenerics::No(NoConstantGenericsReason::IsEnumDiscriminant)
}
AnonConstKind::FieldDefaultValue => ConstantHasGenerics::Yes,
AnonConstKind::InlineConst => ConstantHasGenerics::Yes,
AnonConstKind::ConstArg(_) => {
AnonConstKind::ArrayLength | AnonConstKind::ConstArg(_) => {
if self.r.features.generic_const_exprs()
|| self.r.features.min_generic_const_args()
|| is_trivial_const_arg
Expand All @@ -5170,7 +5219,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}
};

self.with_constant_rib(is_repeat_expr, may_use_generics, None, |this| {
self.with_constant_rib(is_repeat_expr, may_use_generics, None, type_suggestion, |this| {
this.with_lifetime_rib(LifetimeRibKind::elided(LifetimeRes::Infer), |this| {
resolve_expr(this);
});
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ enum ResolutionError<'ra> {
suggestion: &'static str,
current: &'static str,
type_span: Option<Span>,
/// Type ascription to suggest when `type_span` is present (e.g. `usize` or `/* Type */`).
type_name: &'static str,
},
/// Error E0530: `X` bindings cannot shadow `Y`s.
BindingShadowsSomethingUnacceptable {
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/consts/non-const-value-in-const.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ LL | let _ = [0; x];
help: consider using `const` instead of `let`
|
LL - let x = 5;
LL + const x: /* Type */ = 5;
LL + const x: usize = 5;
|

error: aborting due to 2 previous errors
Expand Down
10 changes: 10 additions & 0 deletions tests/ui/consts/suggest-usize-for-array-length.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! Regression test for #159487: when suggesting `const` for a value used as an
//! array length or repeat count, prefer `usize` over `/* Type */`.

fn main() {
let length = 3;
let values: [i32; length] = [0; length];
//~^ ERROR attempt to use a non-constant value in a constant
//~| ERROR attempt to use a non-constant value in a constant
println!("{}", values.len());
}
27 changes: 27 additions & 0 deletions tests/ui/consts/suggest-usize-for-array-length.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/suggest-usize-for-array-length.rs:6:23
|
LL | let values: [i32; length] = [0; length];
| ^^^^^^ non-constant value
|
help: consider using `const` instead of `let`
|
LL - let length = 3;
LL + const length: usize = 3;
|

error[E0435]: attempt to use a non-constant value in a constant
--> $DIR/suggest-usize-for-array-length.rs:6:37
|
LL | let values: [i32; length] = [0; length];
| ^^^^^^ non-constant value
|
help: consider using `const` instead of `let`
|
LL - let length = 3;
LL + const length: usize = 3;
|

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0435`.
2 changes: 1 addition & 1 deletion tests/ui/parser/recover/array-type-no-semi.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ LL | let c: [i32, x];
help: consider using `const` instead of `let`
|
LL - let x = 5;
LL + const x: /* Type */ = 5;
LL + const x: usize = 5;
|

error[E0423]: cannot find value `i32` in this scope
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/repeat-expr/repeat_count.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ LL | let a = [0; n];
help: consider using `const` instead of `let`
|
LL - let n = 1;
LL + const n: /* Type */ = 1;
LL + const n: usize = 1;
|

error[E0308]: mismatched types
Expand Down
Loading