diff options
| author | Urgau <3616612+Urgau@users.noreply.github.com> | 2024-10-16 12:03:43 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-16 12:03:43 +0200 |
| commit | 329e5704604ca677562a8f8e69b18c008f8cca15 (patch) | |
| tree | 07b686976f04678584dd2562b9a9f724ce7f444b | |
| parent | 66dc09f3dacce171389b0861a320aaeb6f95f659 (diff) | |
| parent | 68885216b63f6e75e50b4c0f3c7250ca4ac7afda (diff) | |
| download | rust-329e5704604ca677562a8f8e69b18c008f8cca15.tar.gz rust-329e5704604ca677562a8f8e69b18c008f8cca15.zip | |
Rollup merge of #131754 - compiler-errors:bivariance-bivariance, r=estebank
Don't report bivariance error when nesting a struct with field errors into another struct
We currently have logic to avoid reporting lifetime bivariance ("lifetime parameter ... is never used") errors when a struct has field resolution errors. However, this doesn't apply transitively. This PR implements a simple visitor to do so.
This was reported [here](https://twitter.com/fasterthanlime/status/1846257921086165033) since a `derive(Deserialize, Serialize)` ends up generating helper structs which have bivariant lifetimes due to containing the offending struct (that's being derived on).
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`. |
