Skip to content

Commit 811a45e

Browse files
committed
Prepare to use borrowck to resolve opaque types
1 parent f158ca9 commit 811a45e

File tree

5 files changed

+128
-68
lines changed

5 files changed

+128
-68
lines changed

src/librustc/mir/query.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! Values computed by queries that use MIR.
22
33
use crate::ty::{self, Ty};
4+
use rustc_data_structures::fx::FxHashMap;
45
use rustc_data_structures::sync::Lrc;
56
use rustc_hir as hir;
7+
use rustc_hir::def_id::DefId;
68
use rustc_index::bit_set::BitMatrix;
79
use rustc_index::vec::IndexVec;
810
use rustc_span::{Span, Symbol};
@@ -59,8 +61,12 @@ pub struct GeneratorLayout<'tcx> {
5961
pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
6062
}
6163

62-
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
64+
#[derive(Debug, RustcEncodable, RustcDecodable, HashStable)]
6365
pub struct BorrowCheckResult<'tcx> {
66+
/// All the opaque types that are restricted to concrete types
67+
/// by this function. Unlike the value in `TypeckTables`, this has
68+
/// unerased regions.
69+
pub concrete_opaque_types: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
6470
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
6571
pub used_mut_upvars: SmallVec<[Field; 8]>,
6672
}

src/librustc_mir/borrow_check/mod.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -204,19 +204,24 @@ fn do_mir_borrowck<'a, 'tcx>(
204204
Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
205205

206206
// Compute non-lexical lifetimes.
207-
let nll::NllOutput { regioncx, polonius_output, opt_closure_req, nll_errors } =
208-
nll::compute_regions(
209-
infcx,
210-
def_id,
211-
free_regions,
212-
body,
213-
&promoted,
214-
location_table,
215-
param_env,
216-
&mut flow_inits,
217-
&mdpe.move_data,
218-
&borrow_set,
219-
);
207+
let nll::NllOutput {
208+
regioncx,
209+
opaque_type_values,
210+
polonius_output,
211+
opt_closure_req,
212+
nll_errors,
213+
} = nll::compute_regions(
214+
infcx,
215+
def_id,
216+
free_regions,
217+
body,
218+
&promoted,
219+
location_table,
220+
param_env,
221+
&mut flow_inits,
222+
&mdpe.move_data,
223+
&borrow_set,
224+
);
220225

221226
// Dump MIR results into a file, if that is enabled. This let us
222227
// write unit-tests, as well as helping with debugging.
@@ -404,6 +409,7 @@ fn do_mir_borrowck<'a, 'tcx>(
404409
}
405410

406411
let result = BorrowCheckResult {
412+
concrete_opaque_types: opaque_type_values,
407413
closure_requirements: opt_closure_req,
408414
used_mut_upvars: mbcx.used_mut_upvars,
409415
};

src/librustc_mir/borrow_check/nll.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc::mir::{
66
Location, Promoted, ReadOnlyBodyAndCache,
77
};
88
use rustc::ty::{self, RegionKind, RegionVid};
9+
use rustc_data_structures::fx::FxHashMap;
910
use rustc_errors::Diagnostic;
1011
use rustc_hir::def_id::DefId;
1112
use rustc_index::vec::IndexVec;
@@ -46,6 +47,7 @@ crate type PoloniusOutput = Output<RustcFacts>;
4647
/// closure requirements to propagate, and any generated errors.
4748
crate struct NllOutput<'tcx> {
4849
pub regioncx: RegionInferenceContext<'tcx>,
50+
pub opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
4951
pub polonius_output: Option<Rc<PoloniusOutput>>,
5052
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
5153
pub nll_errors: RegionErrors<'tcx>,
@@ -160,20 +162,21 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
160162
let elements = &Rc::new(RegionValueElements::new(&body));
161163

162164
// Run the MIR type-checker.
163-
let MirTypeckResults { constraints, universal_region_relations } = type_check::type_check(
164-
infcx,
165-
param_env,
166-
body,
167-
promoted,
168-
def_id,
169-
&universal_regions,
170-
location_table,
171-
borrow_set,
172-
&mut all_facts,
173-
flow_inits,
174-
move_data,
175-
elements,
176-
);
165+
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
166+
type_check::type_check(
167+
infcx,
168+
param_env,
169+
body,
170+
promoted,
171+
def_id,
172+
&universal_regions,
173+
location_table,
174+
borrow_set,
175+
&mut all_facts,
176+
flow_inits,
177+
move_data,
178+
elements,
179+
);
177180

178181
if let Some(all_facts) = &mut all_facts {
179182
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation");
@@ -281,6 +284,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
281284

282285
NllOutput {
283286
regioncx,
287+
opaque_type_values,
284288
polonius_output,
285289
opt_closure_req: closure_region_requirements,
286290
nll_errors,

src/librustc_mir/borrow_check/type_check/mod.rs

Lines changed: 64 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ pub(crate) fn type_check<'tcx>(
159159
constraints: &mut constraints,
160160
};
161161

162-
type_check_internal(
162+
let opaque_type_values = type_check_internal(
163163
infcx,
164164
mir_def_id,
165165
param_env,
@@ -174,10 +174,11 @@ pub(crate) fn type_check<'tcx>(
174174
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
175175

176176
translate_outlives_facts(&mut cx);
177+
cx.opaque_type_values
177178
},
178179
);
179180

180-
MirTypeckResults { constraints, universal_region_relations }
181+
MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
181182
}
182183

183184
fn type_check_internal<'a, 'tcx, R>(
@@ -190,7 +191,7 @@ fn type_check_internal<'a, 'tcx, R>(
190191
implicit_region_bound: ty::Region<'tcx>,
191192
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
192193
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
193-
mut extra: impl FnMut(&mut TypeChecker<'a, 'tcx>) -> R,
194+
extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
194195
) -> R {
195196
let mut checker = TypeChecker::new(
196197
infcx,
@@ -213,7 +214,7 @@ fn type_check_internal<'a, 'tcx, R>(
213214
checker.typeck_mir(body);
214215
}
215216

216-
extra(&mut checker)
217+
extra(checker)
217218
}
218219

219220
fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
@@ -800,6 +801,7 @@ struct TypeChecker<'a, 'tcx> {
800801
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
801802
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
802803
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
804+
opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
803805
}
804806

805807
struct BorrowCheckContext<'a, 'tcx> {
@@ -813,6 +815,7 @@ struct BorrowCheckContext<'a, 'tcx> {
813815
crate struct MirTypeckResults<'tcx> {
814816
crate constraints: MirTypeckRegionConstraints<'tcx>,
815817
crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
818+
crate opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
816819
}
817820

818821
/// A collection of region constraints that must be satisfied for the
@@ -959,6 +962,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
959962
borrowck_context,
960963
reported_errors: Default::default(),
961964
universal_region_relations,
965+
opaque_type_values: FxHashMap::default(),
962966
};
963967
checker.check_user_type_annotations();
964968
checker
@@ -1196,6 +1200,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
11961200
let tcx = infcx.tcx;
11971201
let param_env = self.param_env;
11981202
let body = self.body;
1203+
let concrete_opaque_types = &tcx.typeck_tables_of(anon_owner_def_id).concrete_opaque_types;
1204+
let mut opaque_type_values = Vec::new();
1205+
11991206
debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id);
12001207
let opaque_type_map = self.fully_perform_op(
12011208
locations,
@@ -1227,47 +1234,65 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
12271234
);
12281235

12291236
for (&opaque_def_id, opaque_decl) in &opaque_type_map {
1230-
let opaque_defn_ty = tcx.type_of(opaque_def_id);
1231-
let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
1232-
let opaque_defn_ty = renumber::renumber_regions(infcx, &opaque_defn_ty);
1233-
let concrete_is_opaque = infcx
1234-
.resolve_vars_if_possible(&opaque_decl.concrete_ty)
1235-
.is_impl_trait();
1237+
let resolved_ty = infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty);
1238+
let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind {
1239+
def_id == opaque_def_id
1240+
} else {
1241+
false
1242+
};
1243+
let opaque_defn_ty = match concrete_opaque_types.get(&opaque_def_id) {
1244+
None => {
1245+
assert!(
1246+
concrete_is_opaque,
1247+
"Non-defining use of {:?} with revealed type",
1248+
opaque_def_id,
1249+
);
1250+
continue;
1251+
}
1252+
Some(opaque_defn_ty) => opaque_defn_ty,
1253+
};
1254+
debug!("opaque_defn_ty = {:?}", opaque_defn_ty);
1255+
let subst_opaque_defn_ty =
1256+
opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs);
1257+
let renumbered_opaque_defn_ty =
1258+
renumber::renumber_regions(infcx, &subst_opaque_defn_ty);
12361259

12371260
debug!(
1238-
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?} \
1239-
concrete_is_opaque={}",
1240-
opaque_decl.concrete_ty,
1241-
infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty),
1242-
opaque_defn_ty,
1243-
concrete_is_opaque
1261+
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
1262+
opaque_decl.concrete_ty, resolved_ty, renumbered_opaque_defn_ty,
12441263
);
12451264

1246-
// concrete_is_opaque is `true` when we're using an opaque `impl Trait`
1247-
// type without 'revealing' it. For example, code like this:
1248-
//
1249-
// type Foo = impl Debug;
1250-
// fn foo1() -> Foo { ... }
1251-
// fn foo2() -> Foo { foo1() }
1252-
//
1253-
// In `foo2`, we're not revealing the type of `Foo` - we're
1254-
// just treating it as the opaque type.
1255-
//
1256-
// When this occurs, we do *not* want to try to equate
1257-
// the concrete type with the underlying defining type
1258-
// of the opaque type - this will always fail, since
1259-
// the defining type of an opaque type is always
1260-
// some other type (e.g. not itself)
1261-
// Essentially, none of the normal obligations apply here -
1262-
// we're just passing around some unknown opaque type,
1263-
// without actually looking at the underlying type it
1264-
// gets 'revealed' into
1265-
12661265
if !concrete_is_opaque {
12671266
obligations.add(
12681267
infcx
12691268
.at(&ObligationCause::dummy(), param_env)
1270-
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?,
1269+
.eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?,
1270+
);
1271+
opaque_type_values
1272+
.push((opaque_def_id, ty::ResolvedOpaqueTy { ..*opaque_defn_ty }));
1273+
} else {
1274+
// We're using an opaque `impl Trait` type without
1275+
// 'revealing' it. For example, code like this:
1276+
//
1277+
// type Foo = impl Debug;
1278+
// fn foo1() -> Foo { ... }
1279+
// fn foo2() -> Foo { foo1() }
1280+
//
1281+
// In `foo2`, we're not revealing the type of `Foo` - we're
1282+
// just treating it as the opaque type.
1283+
//
1284+
// When this occurs, we do *not* want to try to equate
1285+
// the concrete type with the underlying defining type
1286+
// of the opaque type - this will always fail, since
1287+
// the defining type of an opaque type is always
1288+
// some other type (e.g. not itself)
1289+
// Essentially, none of the normal obligations apply here -
1290+
// we're just passing around some unknown opaque type,
1291+
// without actually looking at the underlying type it
1292+
// gets 'revealed' into
1293+
debug!(
1294+
"eq_opaque_type_and_type: non-defining use of {:?}",
1295+
opaque_def_id,
12711296
);
12721297
}
12731298
}
@@ -1283,6 +1308,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
12831308
),
12841309
)?;
12851310

1311+
self.opaque_type_values.extend(opaque_type_values);
1312+
12861313
let universal_region_relations = self.universal_region_relations;
12871314

12881315
// Finally, if we instantiated the anon types successfully, we

src/librustc_typeck/collect.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,7 +1353,7 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
13531353
}
13541354
// Opaque types desugared from `impl Trait`.
13551355
ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(owner), .. }) => {
1356-
tcx.typeck_tables_of(owner)
1356+
tcx.mir_borrowck(owner)
13571357
.concrete_opaque_types
13581358
.get(&def_id)
13591359
.map(|opaque| opaque.concrete_type)
@@ -1576,7 +1576,7 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
15761576
}
15771577

15781578
fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
1579-
use rustc_hir::{ImplItem, Item, TraitItem};
1579+
use rustc_hir::{Expr, ImplItem, Item, TraitItem};
15801580

15811581
debug!("find_opaque_ty_constraints({:?})", def_id);
15821582

@@ -1602,7 +1602,17 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
16021602
);
16031603
return;
16041604
}
1605-
let ty = self.tcx.typeck_tables_of(def_id).concrete_opaque_types.get(&self.def_id);
1605+
// Calling `mir_borrowck` can lead to cycle errors through
1606+
// const-checking, avoid calling it if we don't have to.
1607+
if !self.tcx.typeck_tables_of(def_id).concrete_opaque_types.contains_key(&self.def_id) {
1608+
debug!(
1609+
"find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`",
1610+
self.def_id, def_id,
1611+
);
1612+
return;
1613+
}
1614+
// Use borrowck to get the type with unerased regions.
1615+
let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id);
16061616
if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
16071617
debug!(
16081618
"find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}",
@@ -1738,6 +1748,13 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
17381748
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
17391749
intravisit::NestedVisitorMap::All(&self.tcx.hir())
17401750
}
1751+
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
1752+
if let hir::ExprKind::Closure(..) = ex.kind {
1753+
let def_id = self.tcx.hir().local_def_id(ex.hir_id);
1754+
self.check(def_id);
1755+
}
1756+
intravisit::walk_expr(self, ex);
1757+
}
17411758
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
17421759
debug!("find_existential_constraints: visiting {:?}", it);
17431760
let def_id = self.tcx.hir().local_def_id(it.hir_id);

0 commit comments

Comments
 (0)