about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-10-15 14:58:41 -0400
committerMichael Goulet <michael@errs.io>2024-10-15 14:58:54 -0400
commit68885216b63f6e75e50b4c0f3c7250ca4ac7afda (patch)
tree0a24c6294ea8f50aaf76c96a0ddf37aa4a83dc08
parenta0c2aba29aa9ea50a7c45c3391dd446f856bef7b (diff)
downloadrust-68885216b63f6e75e50b4c0f3c7250ca4ac7afda.tar.gz
rust-68885216b63f6e75e50b4c0f3c7250ca4ac7afda.zip
Don't report bivariance error when nesting a struct with field errors into another struct
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs60
-rw-r--r--tests/ui/variance/type-resolve-error-two-structs-deep.rs13
-rw-r--r--tests/ui/variance/type-resolve-error-two-structs-deep.stderr9
3 files changed, 72 insertions, 10 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 607068f162a..f788456d4e9 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1875,24 +1875,15 @@ fn check_variances_for_type_defn<'tcx>(
     item: &'tcx hir::Item<'tcx>,
     hir_generics: &hir::Generics<'tcx>,
 ) {
-    let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id);
-
     match item.kind {
         ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
-            for field in tcx.adt_def(item.owner_id).all_fields() {
-                if field.ty(tcx, identity_args).references_error() {
-                    return;
-                }
-            }
+            // Ok
         }
         ItemKind::TyAlias(..) => {
             assert!(
                 tcx.type_alias_is_lazy(item.owner_id),
                 "should not be computing variance of non-weak type alias"
             );
-            if tcx.type_of(item.owner_id).skip_binder().references_error() {
-                return;
-            }
         }
         kind => span_bug!(item.span, "cannot compute the variances of {kind:?}"),
     }
@@ -1955,6 +1946,15 @@ fn check_variances_for_type_defn<'tcx>(
             continue;
         }
 
+        // Look for `ErrorGuaranteed` deeply within this type.
+        if let ControlFlow::Break(ErrorGuaranteed { .. }) = tcx
+            .type_of(item.owner_id)
+            .instantiate_identity()
+            .visit_with(&mut HasErrorDeep { tcx, seen: Default::default() })
+        {
+            continue;
+        }
+
         match hir_param.name {
             hir::ParamName::Error => {}
             _ => {
@@ -1965,6 +1965,46 @@ fn check_variances_for_type_defn<'tcx>(
     }
 }
 
+/// Look for `ErrorGuaranteed` deeply within structs' (unsubstituted) fields.
+struct HasErrorDeep<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    seen: FxHashSet<DefId>,
+}
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasErrorDeep<'tcx> {
+    type Result = ControlFlow<ErrorGuaranteed>;
+
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
+        match *ty.kind() {
+            ty::Adt(def, _) => {
+                if self.seen.insert(def.did()) {
+                    for field in def.all_fields() {
+                        self.tcx.type_of(field.did).instantiate_identity().visit_with(self)?;
+                    }
+                }
+            }
+            ty::Error(guar) => return ControlFlow::Break(guar),
+            _ => {}
+        }
+        ty.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
+        if let Err(guar) = r.error_reported() {
+            ControlFlow::Break(guar)
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+
+    fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result {
+        if let Err(guar) = c.error_reported() {
+            ControlFlow::Break(guar)
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+}
+
 fn report_bivariance<'tcx>(
     tcx: TyCtxt<'tcx>,
     param: &'tcx hir::GenericParam<'tcx>,
diff --git a/tests/ui/variance/type-resolve-error-two-structs-deep.rs b/tests/ui/variance/type-resolve-error-two-structs-deep.rs
new file mode 100644
index 00000000000..47ec532ab96
--- /dev/null
+++ b/tests/ui/variance/type-resolve-error-two-structs-deep.rs
@@ -0,0 +1,13 @@
+// Make sure we don't report bivariance errors when nesting structs w/ unresolved
+// fields into *other* structs.
+
+struct Hello<'a> {
+    missing: Missing<'a>,
+    //~^ ERROR cannot find type `Missing` in this scope
+}
+
+struct Other<'a> {
+    hello: Hello<'a>,
+}
+
+fn main() {}
diff --git a/tests/ui/variance/type-resolve-error-two-structs-deep.stderr b/tests/ui/variance/type-resolve-error-two-structs-deep.stderr
new file mode 100644
index 00000000000..3458d924bb1
--- /dev/null
+++ b/tests/ui/variance/type-resolve-error-two-structs-deep.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `Missing` in this scope
+  --> $DIR/type-resolve-error-two-structs-deep.rs:5:14
+   |
+LL |     missing: Missing<'a>,
+   |              ^^^^^^^ not found in this scope
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0412`.