rust-lang / rust

Empowering everyone to build reliable and efficient software.

Home Page:https://www.rust-lang.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

internal compiler error: no type for node HirId ...

dwrensha opened this issue · comments

I'm seeing an internal compiler error on the following input (found by fuzz-rustc):

struct Foo { 0: u8 }

fn test(f: Foo) {
    Foo{foo: 4, ..f};
}

fn main() {}
$ rustc main.rs
error: expected identifier, found `0`
 --> main.rs:1:14
  |
1 | struct Foo { 0: u8 }
  |              ^ expected identifier

error: internal compiler error: src/librustc_typeck/check/mod.rs:3328: no type for node HirId { owner: DefIndex(4), local_id: 4 }: expr f (hir_id=HirId { owner: DefIndex(4), local_id: 4 }) in fcx 0x7fdb535efe40

thread 'rustc' panicked at 'Box<Any>', src/librustc_errors/lib.rs:881:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.43.0-nightly (8aa9d2014 2020-02-21) running on x86_64-unknown-linux-gnu

error: aborting due to 2 previous errors

The error happens on stable, beta, and nightly.

I'm looking into this! But mostly as a learning exercise. Spent ~4 hours exploring typeck & error handling today to see why this exact combination of things triggers an error. My friend and I will probably have a solution at some point, but it might be a few weeks from now.

If anyone has a good & quick solution, or if it is deemed high-priority, then feel free to ignore me.

According to cargo-bisect-rustc, this regressed between 2019-07-30 and 2019-07-31. Unfortunately, cargo-bisect-rustc seems to be incapable of narrowing it down to a commit because that was more than 167 days ago.

EDIT: cargo-bisect-rustc gave me a misleading result. This error is at least as old as nightly-2019-07-19.

This error started happening in 6007e6f.
cc @estebank

The ICE goes away if I apply this patch:

$ git diff
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 38d73256469..a3bb0c2fb81 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -1311,9 +1311,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         kind_name: &str,
         ty_span: Span,
     ) {
-        if variant.recovered {
-            return;
-        }
         let mut err = self.type_error_struct_with_diag(
             field.ident.span,
             |actual| match ty.kind {

(Though I'd guess that making this change would cause us to regress on the problems that #59266 fixed.)

This change fixes the ICE and avoids regressing on ui/parser/recovered-struct-variant.rs:

$ git diff
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 38d73256469..bd80cc31e3c 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -1218,8 +1218,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 self.field_ty(field.span, v_field, substs)
             } else {
-                error_happened = true;
                 if let Some(prev_span) = seen_fields.get(&ident) {
+                    error_happened = true;
                     let mut err = struct_span_err!(
                         self.tcx.sess,
                         field.ident.span,
@@ -1232,7 +1232,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     err.span_label(*prev_span, format!("first use of `{}`", ident));
 
                     err.emit();
-                } else {
+                } else if !variant.recovered {
+                    error_happened = true;
                     self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name, span);
                 }
 
@@ -1311,9 +1312,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         kind_name: &str,
         ty_span: Span,
     ) {
-        if variant.recovered {
-            return;
-        }
         let mut err = self.type_error_struct_with_diag(
             field.ident.span,
             |actual| match ty.kind {

I'm unsure whether this respects the intended meaning of error_happened, though.

@dwrensha on a very cursory look that patch looks reasonable.

#50643 has some additional relevant context.

Unfortunately, the patch that I proposed above fails on this modification of ui/issues/issue-50618.rs:

struct Point {
    pub x: u64,
    pub y: u64,
    0: u64,
}

fn main() {
    let _ = |t: Point| {
        Point {
            nonexistent: 0,
            ..t
        }
    };
}

triage: P-high. Removing nomination. Added regression stable-to-stable tag.

I think I found a way to resolve this without regressing on #59266. The point of this PR is to not emit an error if it might be invalid to the user. But there are errors in context still. The patch I propose is this:

diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 38d73256469..14615521749 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -1312,6 +1312,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ty_span: Span,
     ) {
         if variant.recovered {
+            self.set_tainted_by_errors();
             return;
         }
         let mut err = self.type_error_struct_with_diag(

This does pass every UI test. I'll open a PR so this can be discussed more easely.