Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix an ICE with a const argument in a trait #61409

Merged
merged 3 commits into from
Jun 4, 2019
Merged
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
155 changes: 82 additions & 73 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1335,88 +1335,97 @@ pub fn checked_type_of<'a, 'tcx>(

Node::Ty(&hir::Ty { node: hir::TyKind::Path(_), .. }) |
Node::Expr(&hir::Expr { node: ExprKind::Struct(..), .. }) |
Node::Expr(&hir::Expr { node: ExprKind::Path(_), .. }) => {
Node::Expr(&hir::Expr { node: ExprKind::Path(_), .. }) |
Node::TraitRef(..) => {
let path = match parent_node {
Node::Ty(&hir::Ty { node: hir::TyKind::Path(ref path), .. }) |
Node::Expr(&hir::Expr { node: ExprKind::Path(ref path), .. }) => {
path
Node::Ty(&hir::Ty {
node: hir::TyKind::Path(QPath::Resolved(_, ref path)),
..
})
| Node::Expr(&hir::Expr {
node: ExprKind::Path(QPath::Resolved(_, ref path)),
..
}) => {
Some(&**path)
}
Node::Expr(&hir::Expr { node: ExprKind::Struct(ref path, ..), .. }) => {
&*path
if let QPath::Resolved(_, ref path) = **path {
Some(&**path)
} else {
None
}
}
_ => unreachable!(),
Node::TraitRef(&hir::TraitRef { ref path, .. }) => Some(path),
_ => None,
};

match path {
QPath::Resolved(_, ref path) => {
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 {
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
),
);
return Some(tcx.types.err);
if let Some(path) = path {
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 {
None
} else {
bug!("no arg matching AnonConst in path")
}
};

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 {
return None;
})?;

// 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())
}
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!(
"unexpected const parent path {:?}", x
),
);
tcx.types.err
Res::Def(_, def_id) => tcx.generics_of(def_id),
Res::Err => return Some(tcx.types.err),
_ if !fail => return None,
res => {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!(
"unexpected const parent path def {:?}",
res,
),
);
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)
} else {
if !fail {
return None;
}
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!(
"unexpected const parent path {:?}",
parent_node,
),
);
return Some(tcx.types.err);
}
}

Expand Down
10 changes: 7 additions & 3 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5250,9 +5250,13 @@ impl<'a> Parser<'a> {
// FIXME(const_generics): to distinguish between idents for types and consts,
// we should introduce a GenericArg::Ident in the AST and distinguish when
// lowering to the HIR. For now, idents for const args are not permitted.
return Err(
self.fatal("identifiers may currently not be used for const generics")
);
if self.token.is_keyword(kw::True) || self.token.is_keyword(kw::False) {
self.parse_literal_maybe_minus()?
} else {
return Err(
self.fatal("identifiers may currently not be used for const generics")
);
}
} else {
self.parse_literal_maybe_minus()?
};
Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/const-generics/condition-in-trait-const-arg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// run-pass

#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash

trait IsZeroTrait<const IS_ZERO: bool>{}

impl IsZeroTrait<{0u8 == 0u8}> for () {}

impl IsZeroTrait<true> for ((),) {}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> $DIR/condition-in-trait-const-arg.rs:3:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^