Skip to content

Commit 50a3c38

Browse files
committed
Propagate lifetime resolution errors into tcx.type_of
Fixes #69136 Previously, lifetime resolution errors would cause an error to be emitted, but would not mark the parent type as 'tainted' in any way. We usually abort compilation before this becomes an issue - however, opaque types can cause us to type-check function bodies before such an abort occurs. Ths can result in trying to instantiate opaque types that have invalid computed generics. Currently, this only causes issues for nested opaque types, but there's no reason to expect the computed generics to be sane when we had unresolved lifetimes (which can result in extra lifetime parameters getting added to the generics). This commit tracks 'unresolved lifetime' errors that occur during lifetime resolution. When we type-check an item, we bail out and return `tcx.types.err` if a lifetime error was reported for that type. This causes us to skip type-checking of types affected by the lifetime error, while still checking unrelated types. Additionally, we now check for errors in 'parent' opaque types (if such a 'parent' exists) when collecting constraints for opaque types. This reflects the fact that opaque types inherit generics from 'parent' opaque types - if an error ocurred while type-checking the parent, we don't attempt to type-check the child.
1 parent 75b98fb commit 50a3c38

File tree

9 files changed

+122
-126
lines changed

9 files changed

+122
-126
lines changed

src/librustc/middle/resolve_lifetime.rs

+4
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,8 @@ pub struct ResolveLifetimes {
8383
/// to the trait object lifetime defaults computed from them.
8484
pub object_lifetime_defaults:
8585
FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Vec<ObjectLifetimeDefault>>>,
86+
87+
/// Contains the ids all HIR items for which we encountered an error
88+
/// when resolving lifetimes.
89+
pub has_lifetime_error: FxHashSet<LocalDefId>,
8690
}

src/librustc/query/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,14 @@ rustc_queries! {
927927
-> Option<&'tcx FxHashMap<ItemLocalId, Vec<ObjectLifetimeDefault>>> {
928928
desc { "looking up lifetime defaults for a region" }
929929
}
930+
/// Determiens if any eccors occured when resolving lifetimes
931+
/// for the specified item. A return value of 'true' means
932+
/// that compilation will eventually fail, and it's safe
933+
/// to create and propagate a TyKind::Error or skip
934+
/// running checks on the affected item.
935+
query has_lifetime_error(_: DefIndex) -> bool {
936+
desc { "determining if a lifetime error was emitted" }
937+
}
930938
}
931939

932940
TypeChecking {

src/librustc_resolve/diagnostics.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1507,7 +1507,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
15071507
)
15081508
}
15091509

1510-
crate fn emit_undeclared_lifetime_error(&self, lifetime_ref: &hir::Lifetime) {
1510+
crate fn emit_undeclared_lifetime_error(&mut self, lifetime_ref: &hir::Lifetime) {
1511+
self.map.has_lifetime_error.insert(lifetime_ref.hir_id.owner_local_def_id());
15111512
let mut err = struct_span_err!(
15121513
self.tcx.sess,
15131514
lifetime_ref.span,

src/librustc_resolve/lifetimes.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ impl RegionExt for Region {
136136
/// actual use. It has the same data, but indexed by `DefIndex`. This
137137
/// is silly.
138138
#[derive(Default)]
139-
struct NamedRegionMap {
139+
crate struct NamedRegionMap {
140140
// maps from every use of a named (not anonymous) lifetime to a
141141
// `Region` describing how that region is bound
142142
defs: HirIdMap<Region>,
@@ -149,11 +149,15 @@ struct NamedRegionMap {
149149
// For each type and trait definition, maps type parameters
150150
// to the trait object lifetime defaults computed from them.
151151
object_lifetime_defaults: HirIdMap<Vec<ObjectLifetimeDefault>>,
152+
153+
/// Contains the ids all HIR items for which we encountered an error
154+
/// when resolving lifetimes.
155+
crate has_lifetime_error: FxHashSet<LocalDefId>,
152156
}
153157

154158
crate struct LifetimeContext<'a, 'tcx> {
155159
crate tcx: TyCtxt<'tcx>,
156-
map: &'a mut NamedRegionMap,
160+
crate map: &'a mut NamedRegionMap,
157161
scope: ScopeRef<'a>,
158162

159163
/// This is slightly complicated. Our representation for poly-trait-refs contains a single
@@ -295,6 +299,11 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
295299
tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id)
296300
},
297301

302+
has_lifetime_error: |tcx, id| {
303+
let id = LocalDefId::from_def_id(DefId::local(id)); // (*)
304+
tcx.resolve_lifetimes(LOCAL_CRATE).has_lifetime_error.contains(&id)
305+
},
306+
298307
..*providers
299308
};
300309

@@ -324,6 +333,7 @@ fn resolve_lifetimes(tcx: TyCtxt<'_>, for_krate: CrateNum) -> &ResolveLifetimes
324333
let map = rl.object_lifetime_defaults.entry(hir_id.owner_local_def_id()).or_default();
325334
map.insert(hir_id.local_id, v);
326335
}
336+
rl.has_lifetime_error = named_region_map.has_lifetime_error;
327337

328338
tcx.arena.alloc(rl)
329339
}
@@ -334,6 +344,7 @@ fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap {
334344
defs: Default::default(),
335345
late_bound: Default::default(),
336346
object_lifetime_defaults: compute_object_lifetime_defaults(tcx),
347+
has_lifetime_error: Default::default(),
337348
};
338349
{
339350
let mut visitor = LifetimeContext {

src/librustc_typeck/collect/type_of.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use rustc_hir::def::{DefKind, Res};
1010
use rustc_hir::def_id::DefId;
1111
use rustc_hir::intravisit;
1212
use rustc_hir::intravisit::Visitor;
13-
use rustc_hir::Node;
1413
use rustc_infer::traits;
14+
use rustc_hir::{ItemKind, Node, CRATE_HIR_ID};
1515
use rustc_span::symbol::{sym, Ident};
1616
use rustc_span::{Span, DUMMY_SP};
1717

@@ -23,6 +23,13 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
2323

2424
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
2525

26+
// We just checked that `DefId` is crate-local
27+
if tcx.has_lifetime_error(def_id.index) {
28+
debug!("type_of: item {:?} has a lifetime-related error, bailing out", def_id);
29+
assert!(tcx.sess.has_errors()); // Sanity check: compilation should be going to fail
30+
return tcx.types.err;
31+
}
32+
2633
let icx = ItemCtxt::new(tcx, def_id);
2734

2835
match tcx.hir().get(hir_id) {
@@ -358,6 +365,26 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
358365

359366
debug!("find_opaque_ty_constraints({:?})", def_id);
360367

368+
// It's possible for one opaque type to be nested inside another
369+
// (e.g. `impl Foo<MyType = impl Bar<A>>`)
370+
// We don't explicitly depend on the type of the parent - however,
371+
// we do depend on its generics. We propagate any errors that occur
372+
// during type-checking of the parent, to ensure that we don't create
373+
// an invalid 'child' opaque type.
374+
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
375+
let parent_id = tcx.hir().get_parent_item(hir_id);
376+
// Type-alias-impl-trait types may have no parent
377+
if parent_id != hir_id && parent_id != CRATE_HIR_ID {
378+
// We only care about checking the parent if it's an opaque type
379+
if let Node::Item(hir::Item { kind: ItemKind::OpaqueTy(..), .. }) = tcx.hir().get(parent_id)
380+
{
381+
if tcx.type_of(tcx.hir().local_def_id(parent_id)) == tcx.types.err {
382+
debug!("find_opaque_ty_constraints: parent opaque type has error, bailing out");
383+
return tcx.types.err;
384+
}
385+
}
386+
}
387+
361388
struct ConstraintLocator<'tcx> {
362389
tcx: TyCtxt<'tcx>,
363390
def_id: DefId,

src/test/ui/associated-type-bounds/duplicate.rs

-12
Original file line numberDiff line numberDiff line change
@@ -108,33 +108,21 @@ type TAW3<T> where T: Iterator<Item: 'static, Item: 'static> = T;
108108
type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
109109
//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
110110
//~| ERROR could not find defining uses
111-
//~| ERROR could not find defining uses
112-
//~| ERROR could not find defining uses
113111
type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
114112
//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
115113
//~| ERROR could not find defining uses
116-
//~| ERROR could not find defining uses
117-
//~| ERROR could not find defining uses
118114
type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
119115
//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
120116
//~| ERROR could not find defining uses
121-
//~| ERROR could not find defining uses
122-
//~| ERROR could not find defining uses
123117
type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
124118
//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
125119
//~| ERROR could not find defining uses
126-
//~| ERROR could not find defining uses
127-
//~| ERROR could not find defining uses
128120
type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
129121
//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
130122
//~| ERROR could not find defining uses
131-
//~| ERROR could not find defining uses
132-
//~| ERROR could not find defining uses
133123
type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
134124
//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]
135125
//~| ERROR could not find defining uses
136-
//~| ERROR could not find defining uses
137-
//~| ERROR could not find defining uses
138126

139127
trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
140128
//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719]

0 commit comments

Comments
 (0)