Skip to content

Commit 32d5f74

Browse files
committed
typeck: Do high-level structural/signature checks before function body checks.
This avoids various ICEs, e.g. premature calls to cat_expr that yield the dreaded "cat_expr Errd" ICE.
1 parent fd69ac1 commit 32d5f74

File tree

1 file changed

+71
-44
lines changed
  • src/librustc_typeck/check

1 file changed

+71
-44
lines changed

src/librustc_typeck/check/mod.rs

+71-44
Original file line numberDiff line numberDiff line change
@@ -441,10 +441,11 @@ fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>)
441441
}
442442

443443
struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
444+
struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
444445

445446
impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
446447
fn visit_item(&mut self, i: &'tcx ast::Item) {
447-
check_item(self.ccx, i);
448+
check_item_type(self.ccx, i);
448449
visit::walk_item(self, i);
449450
}
450451

@@ -460,6 +461,13 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
460461
}
461462
}
462463

464+
impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
465+
fn visit_item(&mut self, i: &'tcx ast::Item) {
466+
check_item_body(self.ccx, i);
467+
visit::walk_item(self, i);
468+
}
469+
}
470+
463471
pub fn check_item_types(ccx: &CrateCtxt) {
464472
let krate = ccx.tcx.map.krate();
465473
let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx);
@@ -474,6 +482,11 @@ pub fn check_item_types(ccx: &CrateCtxt) {
474482

475483
ccx.tcx.sess.abort_if_errors();
476484

485+
let mut visit = CheckItemBodiesVisitor { ccx: ccx };
486+
visit::walk_crate(&mut visit, krate);
487+
488+
ccx.tcx.sess.abort_if_errors();
489+
477490
for drop_method_did in ccx.tcx.destructors.borrow().iter() {
478491
if drop_method_did.krate == ast::LOCAL_CRATE {
479492
let drop_impl_did = ccx.tcx.map.get_parent_did(drop_method_did.node);
@@ -713,13 +726,13 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
713726
}
714727
}
715728

716-
pub fn check_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
717-
debug!("check_item(it.id={}, it.ident={})",
729+
pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
730+
debug!("check_item_type(it.id={}, it.ident={})",
718731
it.id,
719732
ty::item_path_str(ccx.tcx, local_def(it.id)));
720733
let _indenter = indenter();
721-
722734
match it.node {
735+
// Consts can play a role in type-checking, so they are included here.
723736
ast::ItemStatic(_, _, ref e) |
724737
ast::ItemConst(_, ref e) => check_const(ccx, it.span, &**e, it.id),
725738
ast::ItemEnum(ref enum_definition, _) => {
@@ -728,16 +741,9 @@ pub fn check_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
728741
&enum_definition.variants,
729742
it.id);
730743
}
731-
ast::ItemFn(ref decl, _, _, _, ref body) => {
732-
let fn_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
733-
let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id);
734-
check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env);
735-
}
744+
ast::ItemFn(_, _, _, _, _) => {} // entirely within check_item_body
736745
ast::ItemImpl(_, _, _, _, _, ref impl_items) => {
737-
debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
738-
739-
let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
740-
746+
debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
741747
match ty::impl_trait_ref(ccx.tcx, local_def(it.id)) {
742748
Some(impl_trait_ref) => {
743749
check_impl_items_against_trait(ccx,
@@ -747,39 +753,9 @@ pub fn check_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
747753
}
748754
None => { }
749755
}
750-
751-
for impl_item in impl_items {
752-
match impl_item.node {
753-
ast::MethodImplItem(ref sig, ref body) => {
754-
check_method_body(ccx, &impl_pty.generics, sig, body,
755-
impl_item.id, impl_item.span);
756-
}
757-
ast::TypeImplItem(_) |
758-
ast::MacImplItem(_) => {
759-
// Nothing to do here.
760-
}
761-
}
762-
}
763-
764756
}
765-
ast::ItemTrait(_, ref generics, _, ref trait_items) => {
757+
ast::ItemTrait(_, ref generics, _, _) => {
766758
check_trait_on_unimplemented(ccx, generics, it);
767-
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
768-
for trait_item in trait_items {
769-
match trait_item.node {
770-
ast::MethodTraitItem(_, None) => {
771-
// Nothing to do, since required methods don't have
772-
// bodies to check.
773-
}
774-
ast::MethodTraitItem(ref sig, Some(ref body)) => {
775-
check_method_body(ccx, &trait_def.generics, sig, body,
776-
trait_item.id, trait_item.span);
777-
}
778-
ast::TypeTraitItem(..) => {
779-
// Nothing to do.
780-
}
781-
}
782-
}
783759
}
784760
ast::ItemStruct(..) => {
785761
check_struct(ccx, it.id, it.span);
@@ -814,6 +790,57 @@ pub fn check_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
814790
}
815791
}
816792

793+
pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
794+
debug!("check_item_body(it.id={}, it.ident={})",
795+
it.id,
796+
ty::item_path_str(ccx.tcx, local_def(it.id)));
797+
let _indenter = indenter();
798+
match it.node {
799+
ast::ItemFn(ref decl, _, _, _, ref body) => {
800+
let fn_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
801+
let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id);
802+
check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env);
803+
}
804+
ast::ItemImpl(_, _, _, _, _, ref impl_items) => {
805+
debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
806+
807+
let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
808+
809+
for impl_item in impl_items {
810+
match impl_item.node {
811+
ast::MethodImplItem(ref sig, ref body) => {
812+
check_method_body(ccx, &impl_pty.generics, sig, body,
813+
impl_item.id, impl_item.span);
814+
}
815+
ast::TypeImplItem(_) |
816+
ast::MacImplItem(_) => {
817+
// Nothing to do here.
818+
}
819+
}
820+
}
821+
}
822+
ast::ItemTrait(_, _, _, ref trait_items) => {
823+
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
824+
for trait_item in trait_items {
825+
match trait_item.node {
826+
ast::MethodTraitItem(_, None) => {
827+
// Nothing to do, since required methods don't have
828+
// bodies to check.
829+
}
830+
ast::MethodTraitItem(ref sig, Some(ref body)) => {
831+
check_method_body(ccx, &trait_def.generics, sig, body,
832+
trait_item.id, trait_item.span);
833+
}
834+
ast::TypeTraitItem(..) => {
835+
// Nothing to do.
836+
}
837+
}
838+
}
839+
}
840+
_ => {/* nothing to do */ }
841+
}
842+
}
843+
817844
fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
818845
generics: &ast::Generics,
819846
item: &ast::Item) {

0 commit comments

Comments
 (0)