avoid creating an Instance only to immediately disassemble it again

This commit is contained in:
Ralf Jung 2024-07-13 18:32:10 +02:00
parent 86ce911f90
commit 67c99d6338
13 changed files with 54 additions and 114 deletions

View File

@ -1,5 +1,4 @@
An associated `const`, `const` parameter or `static` has been referenced
in a pattern.
A generic parameter or `static` has been referenced in a pattern.
Erroneous code example:
@ -15,25 +14,25 @@ trait Bar {
fn test<A: Bar>(arg: Foo) {
match arg {
A::X => println!("A::X"), // error: E0158: associated consts cannot be
// referenced in patterns
A::X => println!("A::X"), // error: E0158: constant pattern depends
// on a generic parameter
Foo::Two => println!("Two")
}
}
```
Associated `const`s cannot be referenced in patterns because it is impossible
Generic parameters cannot be referenced in patterns because it is impossible
for the compiler to prove exhaustiveness (that some pattern will always match).
Take the above example, because Rust does type checking in the *generic*
method, not the *monomorphized* specific instance. So because `Bar` could have
theoretically infinite implementations, there's no way to always be sure that
theoretically arbitrary implementations, there's no way to always be sure that
`A::X` is `Foo::One`. So this code must be rejected. Even if code can be
proven exhaustive by a programmer, the compiler cannot currently prove this.
The same holds true of `const` parameters and `static`s.
The same holds true of `static`s.
If you want to match against an associated `const`, `const` parameter or
`static` consider using a guard instead:
If you want to match against a `const` that depends on a generic parameter or a
`static`, consider using a guard instead:
```
trait Trait {

View File

@ -4,8 +4,6 @@ mir_build_already_borrowed = cannot borrow value as mutable because it is also b
mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable
mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
mir_build_bindings_with_variant_name =
pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`
.suggestion = to match on the variant, qualify the path

View File

@ -566,13 +566,6 @@ pub(crate) struct StaticInPattern {
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(mir_build_assoc_const_in_pattern, code = E0158)]
pub(crate) struct AssocConstInPattern {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(mir_build_const_param_in_pattern, code = E0158)]
pub(crate) struct ConstParamInPattern {
@ -597,7 +590,7 @@ pub(crate) struct UnreachablePattern {
}
#[derive(Diagnostic)]
#[diag(mir_build_const_pattern_depends_on_generic_parameter)]
#[diag(mir_build_const_pattern_depends_on_generic_parameter, code = E0158)]
pub(crate) struct ConstPatternDependsOnGenericParameter {
#[primary_span]
pub(crate) span: Span,

View File

@ -548,37 +548,8 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
_ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])),
};
// Use `Reveal::All` here because patterns are always monomorphic even if their function
// isn't.
let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx);
// N.B. There is no guarantee that args collected in typeck results are fully normalized,
// so they need to be normalized in order to pass to `Instance::resolve`, which will ICE
// if given unnormalized types.
let args = self
.tcx
.normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_args(id));
let instance = match ty::Instance::try_resolve(self.tcx, param_env_reveal_all, def_id, args)
{
Ok(Some(i)) => i,
Ok(None) => {
// It should be assoc consts if there's no error but we cannot resolve it.
debug_assert!(is_associated_const);
let e = self.tcx.dcx().emit_err(AssocConstInPattern { span });
return pat_from_kind(PatKind::Error(e));
}
Err(_) => {
let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span });
return pat_from_kind(PatKind::Error(e));
}
};
let c = ty::Const::new_unevaluated(
self.tcx,
ty::UnevaluatedConst { def: instance.def_id(), args: instance.args },
);
let args = self.typeck_results.node_args(id);
let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
let pattern = self.const_to_pat(c, ty, id, span);
if !is_associated_const {

View File

@ -3449,7 +3449,6 @@ ui/pattern/issue-6449.rs
ui/pattern/issue-66270-pat-struct-parser-recovery.rs
ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs
ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs
ui/pattern/issue-68393-let-pat-assoc-constant.rs
ui/pattern/issue-72565.rs
ui/pattern/issue-72574-1.rs
ui/pattern/issue-72574-2.rs

View File

@ -1,15 +0,0 @@
error[E0158]: associated consts cannot be referenced in patterns
--> $DIR/associated-const-type-parameter-arms.rs:20:9
|
LL | A::X => println!("A::X"),
| ^^^^
error[E0158]: associated consts cannot be referenced in patterns
--> $DIR/associated-const-type-parameter-arms.rs:22:9
|
LL | B::X => println!("B::X"),
| ^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0158`.

View File

@ -18,12 +18,18 @@ impl Foo for Def {
pub fn test<A: Foo, B: Foo>(arg: EFoo) {
match arg {
A::X => println!("A::X"),
//~^ error: associated consts cannot be referenced in patterns [E0158]
//~^ error: constant pattern depends on a generic parameter
B::X => println!("B::X"),
//~^ error: associated consts cannot be referenced in patterns [E0158]
//~^ error: constant pattern depends on a generic parameter
_ => (),
}
}
pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
//~^ ERROR constant pattern depends on a generic parameter
let A::X = arg;
//~^ ERROR constant pattern depends on a generic parameter
}
fn main() {
}

View File

@ -0,0 +1,27 @@
error[E0158]: constant pattern depends on a generic parameter
--> $DIR/associated-const-type-parameter-pattern.rs:20:9
|
LL | A::X => println!("A::X"),
| ^^^^
error[E0158]: constant pattern depends on a generic parameter
--> $DIR/associated-const-type-parameter-pattern.rs:22:9
|
LL | B::X => println!("B::X"),
| ^^^^
error[E0158]: constant pattern depends on a generic parameter
--> $DIR/associated-const-type-parameter-pattern.rs:30:9
|
LL | let A::X = arg;
| ^^^^
error[E0158]: constant pattern depends on a generic parameter
--> $DIR/associated-const-type-parameter-pattern.rs:28:48
|
LL | pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
| ^^^^
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0158`.

View File

@ -1,10 +1,10 @@
error: constant pattern depends on a generic parameter
error[E0158]: constant pattern depends on a generic parameter
--> $DIR/issue-73976-polymorphic.rs:20:37
|
LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
| ^^^^^^^^^^^^^^^^^^^^^
error: constant pattern depends on a generic parameter
error[E0158]: constant pattern depends on a generic parameter
--> $DIR/issue-73976-polymorphic.rs:31:42
|
LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
@ -12,3 +12,4 @@ LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0158`.

View File

@ -1,4 +1,4 @@
error: constant pattern depends on a generic parameter
error[E0158]: constant pattern depends on a generic parameter
--> $DIR/issue-79137-toogeneric.rs:12:43
|
LL | matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
@ -6,3 +6,4 @@ LL | matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0158`.

View File

@ -1,10 +1,10 @@
error: constant pattern depends on a generic parameter
error[E0158]: constant pattern depends on a generic parameter
--> $DIR/const-match-pat-generic.rs:7:9
|
LL | const { V } => {},
| ^^^^^^^^^^^
error: constant pattern depends on a generic parameter
error[E0158]: constant pattern depends on a generic parameter
--> $DIR/const-match-pat-generic.rs:19:9
|
LL | const { f(V) } => {},
@ -12,3 +12,4 @@ LL | const { f(V) } => {},
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0158`.

View File

@ -1,26 +0,0 @@
pub enum EFoo {
A,
}
pub trait Foo {
const X: EFoo;
}
struct Abc;
impl Foo for Abc {
const X: EFoo = EFoo::A;
}
struct Def;
impl Foo for Def {
const X: EFoo = EFoo::A;
}
pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
//~^ ERROR associated consts cannot be referenced in patterns
let A::X = arg;
//~^ ERROR associated consts cannot be referenced in patterns
}
fn main() {}

View File

@ -1,15 +0,0 @@
error[E0158]: associated consts cannot be referenced in patterns
--> $DIR/issue-68393-let-pat-assoc-constant.rs:22:9
|
LL | let A::X = arg;
| ^^^^
error[E0158]: associated consts cannot be referenced in patterns
--> $DIR/issue-68393-let-pat-assoc-constant.rs:20:40
|
LL | pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
| ^^^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0158`.