Skip to content

Strictly proof not tainted by errors in TypeckResults #126381

Open
@Luv-Ray

Description

@Luv-Ray

I get here from #125888.

For now there is a hack when calling tcx.typeck():

// HACK: We specifically don't want the (opaque) error from tainting our
// inference context. That'll prevent us from doing opaque type inference
// later on in borrowck, which affects diagnostic spans pretty negatively.
if let Some(e) = fcx.tainted_by_errors() {
wbcx.typeck_results.tainted_by_errors = Some(e);
}

so that in returned TypeckResults, the tainted_by_errors may be None even though there is actually some errors. And this could cause many ICEs, because some functions trust that there is no type errors, and whenever it encounters an error, it won't throw an error report and just panic (#125888 is an example).


In this tainted_by_errors function, I try to change the condition to if self.dcx().err_count_excluding_lint_errs() > 0, then return the ErrorGuaranteed, and find that it could resolve 62 ICEs.

Resolved ICE list


    [crashes] tests/crashes/110630.rs
    [crashes] tests/crashes/111709.rs
    [crashes] tests/crashes/111709-2.rs
    [crashes] tests/crashes/112623.rs
    [crashes] tests/crashes/113379.rs
    [crashes] tests/crashes/114663.rs
    [crashes] tests/crashes/115808.rs
    [crashes] tests/crashes/117795.rs
    [crashes] tests/crashes/118545.rs
    [crashes] tests/crashes/119701.rs
    [crashes] tests/crashes/119729.rs
    [crashes] tests/crashes/119786.rs
    [crashes] tests/crashes/120793-2.rs
    [crashes] tests/crashes/120793.rs
    [crashes] tests/crashes/120792.rs
    [crashes] tests/crashes/120873.rs
    [crashes] tests/crashes/121097.rs
    [crashes] tests/crashes/121127.rs
    [crashes] tests/crashes/121063.rs
    [crashes] tests/crashes/121052.rs
    [crashes] tests/crashes/121411.rs
    [crashes] tests/crashes/121429.rs
    [crashes] tests/crashes/121613-2.rs
    [crashes] tests/crashes/121613.rs
    [crashes] tests/crashes/121623.rs
    [crashes] tests/crashes/121816.rs
    [crashes] tests/crashes/121957-1.rs
    [crashes] tests/crashes/121957-2.rs
    [crashes] tests/crashes/122044.rs
    [crashes] tests/crashes/122587-1.rs
    [crashes] tests/crashes/121858.rs
    [crashes] tests/crashes/122259.rs
    [crashes] tests/crashes/122630.rs
    [crashes] tests/crashes/122681.rs
    [crashes] tests/crashes/122904-2.rs
    [crashes] tests/crashes/122904.rs
    [crashes] tests/crashes/122909.rs
    [crashes] tests/crashes/123255.rs
    [crashes] tests/crashes/123276.rs
    [crashes] tests/crashes/123690.rs
    [crashes] tests/crashes/124004.rs
    [crashes] tests/crashes/124021.rs
    [crashes] tests/crashes/124083.rs
    [crashes] tests/crashes/124164.rs
    [crashes] tests/crashes/124262.rs
    [crashes] tests/crashes/124182.rs
    [crashes] tests/crashes/124340.rs
    [crashes] tests/crashes/124563.rs
    [crashes] tests/crashes/124583.rs
    [crashes] tests/crashes/124436.rs
    [crashes] tests/crashes/124894.rs
    [crashes] tests/crashes/125155.rs
    [crashes] tests/crashes/125185.rs
    [crashes] tests/crashes/125553.rs
    [crashes] tests/crashes/125758.rs
    [crashes] tests/crashes/125801.rs
    [crashes] tests/crashes/125768.rs
    [crashes] tests/crashes/125769.rs
    [crashes] tests/crashes/125874.rs
    [crashes] tests/crashes/125888.rs
    [crashes] tests/crashes/125914.rs
    [crashes] tests/crashes/125992.rs

/// Returns `true` if errors have been reported since this infcx was
/// created. This is sometimes used as a heuristic to skip
/// reporting errors that often occur as a result of earlier
/// errors, but where it's hard to be 100% sure (e.g., unresolved
/// inference variables, regionck errors).
#[must_use = "this method does not have any side effects"]
pub fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
if let Some(guar) = self.tainted_by_errors.get() {
Some(guar)
} else if self.dcx().err_count_excluding_lint_errs() > self.err_count_on_creation {
// Errors reported since this infcx was made. Lint errors are
// excluded to avoid some being swallowed in the presence of
// non-lint errors. (It's arguable whether or not this exclusion is
// important.)
let guar = self.dcx().has_errors().unwrap();
self.set_tainted_by_errors(guar);
Some(guar)
} else {
None
}
}


But it will also break many ui tests, because as the hack said, it will affect diagnostic spans pretty negatively. So I think a proper way to resolve that is return a new defined enum rather than Option, such as

/// If any errors occurred while type-checking this body,
/// this field will be set to `Some(ErrorGuaranteed)`.
pub tainted_by_errors: Option<ErrorGuaranteed>,

enum TaintedByErrors {
    Normal(ErrorGuaranteed),
    Opaque(ErrorGuaranteed),
    StrictlyNoError,
}

So that we can choose to either early return or do more diagnostics.

@rustbot label +I-ICE +T-compiler

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions