Fix ICE with struct ctors and const generics.

This commit fixes a ICE where struct constructors were resulting in an
ICE with const generics. Previously, a `match` in `type_of` did not have
an arm for the `DefKind::Ctor` resolutions and therefore would assume
that the type did not have generics.
This commit is contained in:
David Wood
2019-05-14 21:34:43 +01:00
parent 4b9d80325a
commit 41aaf7bc46
6 changed files with 74 additions and 73 deletions
+7
View File
@@ -425,6 +425,13 @@ pub fn id(&self) -> HirId {
GenericArg::Const(c) => c.value.hir_id,
}
}
pub fn is_const(&self) -> bool {
match self {
GenericArg::Const(_) => true,
_ => false,
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
+47 -51
View File
@@ -27,7 +27,7 @@
use rustc::ty::util::Discr;
use rustc::ty::util::IntTypeExt;
use rustc::ty::subst::UnpackedKind;
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
use rustc::ty::{self, AdtKind, DefIdTree, ToPolyTraitRef, Ty, TyCtxt};
use rustc::ty::{ReprOptions, ToPredicate};
use rustc::util::captures::Captures;
use rustc::util::nodemap::FxHashMap;
@@ -1349,65 +1349,61 @@ pub fn checked_type_of<'a, 'tcx>(
match path {
QPath::Resolved(_, ref path) => {
let mut arg_index = 0;
let mut found_const = false;
for seg in &path.segments {
if let Some(generic_args) = &seg.args {
let args = &generic_args.args;
for arg in args {
if let GenericArg::Const(ct) = arg {
if ct.value.hir_id == hir_id {
found_const = true;
break;
}
arg_index += 1;
}
}
}
}
// Sanity check to make sure everything is as expected.
if !found_const {
if !fail {
return None;
}
bug!("no arg matching AnonConst in path")
}
match path.res {
// We've encountered an `AnonConst` in some path, so we need to
// figure out which generic parameter it corresponds to and return
// the relevant type.
Res::Def(DefKind::Struct, def_id)
| Res::Def(DefKind::Union, def_id)
| Res::Def(DefKind::Enum, def_id)
| Res::Def(DefKind::Fn, def_id) => {
let generics = tcx.generics_of(def_id);
let mut param_index = 0;
for param in &generics.params {
if let ty::GenericParamDefKind::Const = param.kind {
if param_index == arg_index {
return Some(tcx.type_of(param.def_id));
}
param_index += 1;
}
}
// This is no generic parameter associated with the arg. This is
// probably from an extra arg where one is not needed.
return Some(tcx.types.err);
}
Res::Err => tcx.types.err,
x => {
let arg_index = path.segments.iter()
.filter_map(|seg| seg.args.as_ref())
.map(|generic_args| generic_args.args.as_ref())
.find_map(|args| {
args.iter()
.filter(|arg| arg.is_const())
.enumerate()
.filter(|(_, arg)| arg.id() == hir_id)
.map(|(index, _)| index)
.next()
})
.or_else(|| {
if !fail {
return None;
None
} else {
bug!("no arg matching AnonConst in path")
}
})?;
// We've encountered an `AnonConst` in some path, so we need to
// figure out which generic parameter it corresponds to and return
// the relevant type.
let generics = match path.res {
Res::Def(DefKind::Ctor(..), def_id) =>
tcx.generics_of(tcx.parent(def_id).unwrap()),
Res::Def(_, def_id) =>
tcx.generics_of(def_id),
Res::Err =>
return Some(tcx.types.err),
_ if !fail =>
return None,
x => {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!(
"unexpected const parent path def {:?}", x
),
);
tcx.types.err
return Some(tcx.types.err);
}
}
};
generics.params.iter()
.filter(|param| {
if let ty::GenericParamDefKind::Const = param.kind {
true
} else {
false
}
})
.nth(arg_index)
.map(|param| tcx.type_of(param.def_id))
// This is no generic parameter associated with the arg. This is
// probably from an extra arg where one is not needed.
.unwrap_or(tcx.types.err)
}
x => {
if !fail {
@@ -1,8 +1,9 @@
// compile-pass
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
// We should probably be able to infer the types here. However, this test is checking that we don't
// get an ICE in this case. It may be modified later to not be an error.
// This test confirms that the types can be inferred correctly for this example with const
// generics. Previously this would ICE, and more recently error.
struct Foo<const NUM_BYTES: usize>(pub [u8; NUM_BYTES]);
@@ -1,25 +1,6 @@
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/cannot-infer-type-for-const-param.rs:1:12
--> $DIR/cannot-infer-type-for-const-param.rs:2:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
error[E0282]: type annotations needed
--> $DIR/cannot-infer-type-for-const-param.rs:10:19
|
LL | let _ = Foo::<3>([1, 2, 3]);
| ^ cannot infer type for `{integer}`
error[E0308]: mismatched types
--> $DIR/cannot-infer-type-for-const-param.rs:10:22
|
LL | let _ = Foo::<3>([1, 2, 3]);
| ^^^^^^^^^ expected `3`, found `3usize`
|
= note: expected type `[u8; _]`
found type `[u8; 3]`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.
@@ -0,0 +1,10 @@
// compile-pass
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
struct Generic<const V: usize>;
fn main() {
let _ = Generic::<0>;
}
@@ -0,0 +1,6 @@
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/issue-60818-struct-constructors.rs:3:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^