Skip to content

Commit 329e570

Browse files
authored
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).
2 parents 66dc09f + 6888521 commit 329e570

File tree

3 files changed

+72
-10
lines changed

3 files changed

+72
-10
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

+50-10
Original file line numberDiff line numberDiff line change
@@ -1875,24 +1875,15 @@ fn check_variances_for_type_defn<'tcx>(
18751875
item: &'tcx hir::Item<'tcx>,
18761876
hir_generics: &hir::Generics<'tcx>,
18771877
) {
1878-
let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id);
1879-
18801878
match item.kind {
18811879
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
1882-
for field in tcx.adt_def(item.owner_id).all_fields() {
1883-
if field.ty(tcx, identity_args).references_error() {
1884-
return;
1885-
}
1886-
}
1880+
// Ok
18871881
}
18881882
ItemKind::TyAlias(..) => {
18891883
assert!(
18901884
tcx.type_alias_is_lazy(item.owner_id),
18911885
"should not be computing variance of non-weak type alias"
18921886
);
1893-
if tcx.type_of(item.owner_id).skip_binder().references_error() {
1894-
return;
1895-
}
18961887
}
18971888
kind => span_bug!(item.span, "cannot compute the variances of {kind:?}"),
18981889
}
@@ -1955,6 +1946,15 @@ fn check_variances_for_type_defn<'tcx>(
19551946
continue;
19561947
}
19571948

1949+
// Look for `ErrorGuaranteed` deeply within this type.
1950+
if let ControlFlow::Break(ErrorGuaranteed { .. }) = tcx
1951+
.type_of(item.owner_id)
1952+
.instantiate_identity()
1953+
.visit_with(&mut HasErrorDeep { tcx, seen: Default::default() })
1954+
{
1955+
continue;
1956+
}
1957+
19581958
match hir_param.name {
19591959
hir::ParamName::Error => {}
19601960
_ => {
@@ -1965,6 +1965,46 @@ fn check_variances_for_type_defn<'tcx>(
19651965
}
19661966
}
19671967

1968+
/// Look for `ErrorGuaranteed` deeply within structs' (unsubstituted) fields.
1969+
struct HasErrorDeep<'tcx> {
1970+
tcx: TyCtxt<'tcx>,
1971+
seen: FxHashSet<DefId>,
1972+
}
1973+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasErrorDeep<'tcx> {
1974+
type Result = ControlFlow<ErrorGuaranteed>;
1975+
1976+
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
1977+
match *ty.kind() {
1978+
ty::Adt(def, _) => {
1979+
if self.seen.insert(def.did()) {
1980+
for field in def.all_fields() {
1981+
self.tcx.type_of(field.did).instantiate_identity().visit_with(self)?;
1982+
}
1983+
}
1984+
}
1985+
ty::Error(guar) => return ControlFlow::Break(guar),
1986+
_ => {}
1987+
}
1988+
ty.super_visit_with(self)
1989+
}
1990+
1991+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
1992+
if let Err(guar) = r.error_reported() {
1993+
ControlFlow::Break(guar)
1994+
} else {
1995+
ControlFlow::Continue(())
1996+
}
1997+
}
1998+
1999+
fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result {
2000+
if let Err(guar) = c.error_reported() {
2001+
ControlFlow::Break(guar)
2002+
} else {
2003+
ControlFlow::Continue(())
2004+
}
2005+
}
2006+
}
2007+
19682008
fn report_bivariance<'tcx>(
19692009
tcx: TyCtxt<'tcx>,
19702010
param: &'tcx hir::GenericParam<'tcx>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Make sure we don't report bivariance errors when nesting structs w/ unresolved
2+
// fields into *other* structs.
3+
4+
struct Hello<'a> {
5+
missing: Missing<'a>,
6+
//~^ ERROR cannot find type `Missing` in this scope
7+
}
8+
9+
struct Other<'a> {
10+
hello: Hello<'a>,
11+
}
12+
13+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0412]: cannot find type `Missing` in this scope
2+
--> $DIR/type-resolve-error-two-structs-deep.rs:5:14
3+
|
4+
LL | missing: Missing<'a>,
5+
| ^^^^^^^ not found in this scope
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0412`.

0 commit comments

Comments
 (0)