Skip to content

Commit

Permalink
Rollup merge of rust-lang#131754 - compiler-errors:bivariance-bivaria…
Browse files Browse the repository at this point in the history
…nce, 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).
  • Loading branch information
matthiaskrgr authored Oct 16, 2024
2 parents 8ab5293 + 6888521 commit f69d8db
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 10 deletions.
60 changes: 50 additions & 10 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:?}"),
}
Expand Down Expand Up @@ -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 => {}
_ => {
Expand All @@ -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>,
Expand Down
13 changes: 13 additions & 0 deletions tests/ui/variance/type-resolve-error-two-structs-deep.rs
Original file line number Diff line number Diff line change
@@ -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() {}
9 changes: 9 additions & 0 deletions tests/ui/variance/type-resolve-error-two-structs-deep.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit f69d8db

Please sign in to comment.