Avoid some duplicated typechecking work

There was a FIXME noting that ty::enum_variants and typeck::check::
check_enum_variants both call eval_const_expr. I tried refactoring the
code so that check_enum_variants does all the work and enum_variants
just looks up cached results, but this turned out not to be easy because
several ty functions call enum_variants and it might get invoked on an
enum before that enum item has been typechecked. Instead, I just made
check_enum_variants update the enum_var_cache so that enum_variants
will never call eval_const_expr twice on the same const.
This commit is contained in:
Tim Chevalier 2012-06-14 16:20:01 -07:00
parent aeb9a2b72c
commit 97bcb20244
2 changed files with 18 additions and 5 deletions

View File

@ -2693,9 +2693,11 @@ fn enum_variants(cx: ctxt, id: ast::def_id) -> @[variant_info] {
let result = if ast::local_crate != id.crate {
@csearch::get_enum_variants(cx, id)
} else {
// FIXME: Now that the variants are run through the type checker (to
// check the disr_expr if it exists), this code should likely be
// moved there to avoid having to call eval_const_expr twice.
/*
Although both this code and check_enum_variants in typeck/check
call eval_const_expr, it should never get called twice for the same
expr, since check_enum_variants also updates the enum_var_cache
*/
alt cx.items.get(id.node) {
ast_map::node_item(@{node: ast::item_enum(variants, _, _), _}, _) {
let mut disr_val = -1;

View File

@ -1200,14 +1200,14 @@ fn check_expr_fn(fcx: @fn_ctxt,
none {
alt sty {
ty::ty_enum(*) {
tcx.sess.span_fatal(
tcx.sess.span_err(
expr.span,
"can only dereference enums \
with a single variant which has a \
single argument");
}
_ {
tcx.sess.span_fatal(
tcx.sess.span_err(
expr.span,
#fmt["type %s cannot be dereferenced",
fcx.infcx.ty_to_str(oper_t)]);
@ -1892,6 +1892,7 @@ fn check_enum_variants(ccx: @crate_ctxt,
let fcx = blank_fn_ctxt(ccx, rty);
let mut disr_vals: [int] = [];
let mut disr_val = 0;
let mut variants = [];
for vs.each {|v|
alt v.node.disr_expr {
some(e) {
@ -1920,9 +1921,19 @@ fn check_enum_variants(ccx: @crate_ctxt,
"discriminator value already exists.");
}
disr_vals += [disr_val];
let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id);
let arg_tys = if v.node.args.len() > 0u {
ty::ty_fn_args(ctor_ty).map {|a| a.ty }
} else { [] };
variants += [@{args: arg_tys, ctor_ty: ctor_ty,
name: v.node.name, id: local_def(v.node.id),
disr_val: disr_val}];
disr_val += 1;
}
// cache so that ty::enum_variants won't repeat this work
ccx.tcx.enum_var_cache.insert(local_def(id), @variants);
// Check that it is possible to represent this enum:
let mut outer = true, did = local_def(id);
if ty::type_structurally_contains(ccx.tcx, rty, {|sty|