Skip to content

Commit

Permalink
Rollup merge of rust-lang#61409 - varkor:condition-trait-param-ice, r…
Browse files Browse the repository at this point in the history
…=oli-obk

Fix an ICE with a const argument in a trait

This goes some way towards fixing rust-lang#61383 (the reduced test case is fixed).
  • Loading branch information
Centril committed Jun 4, 2019
2 parents 6e06f52 + 2b27c62 commit da9869e
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 76 deletions.
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 @@ -5244,9 +5244,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)]
| ^^^^^^^^^^^^^^

0 comments on commit da9869e

Please sign in to comment.