Skip to content

Commit 75ac0cc

Browse files
committed
Prepare to use borrowck to resolve opaque types
1 parent 43a3348 commit 75ac0cc

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
@@ -195,19 +195,24 @@ fn do_mir_borrowck<'a, 'tcx>(
195195
Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
196196

197197
// Compute non-lexical lifetimes.
198-
let nll::NllOutput { regioncx, polonius_output, opt_closure_req, nll_errors } =
199-
nll::compute_regions(
200-
infcx,
201-
def_id,
202-
free_regions,
203-
body,
204-
&promoted,
205-
location_table,
206-
param_env,
207-
&mut flow_inits,
208-
&mdpe.move_data,
209-
&borrow_set,
210-
);
198+
let nll::NllOutput {
199+
regioncx,
200+
opaque_type_values,
201+
polonius_output,
202+
opt_closure_req,
203+
nll_errors,
204+
} = nll::compute_regions(
205+
infcx,
206+
def_id,
207+
free_regions,
208+
body,
209+
&promoted,
210+
location_table,
211+
param_env,
212+
&mut flow_inits,
213+
&mdpe.move_data,
214+
&borrow_set,
215+
);
211216

212217
// Dump MIR results into a file, if that is enabled. This let us
213218
// write unit-tests, as well as helping with debugging.
@@ -389,6 +394,7 @@ fn do_mir_borrowck<'a, 'tcx>(
389394
}
390395

391396
let result = BorrowCheckResult {
397+
concrete_opaque_types: opaque_type_values,
392398
closure_requirements: opt_closure_req,
393399
used_mut_upvars: mbcx.used_mut_upvars,
394400
};

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
@@ -158,7 +158,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
158158
constraints: &mut constraints,
159159
};
160160

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

175175
translate_outlives_facts(&mut cx);
176+
cx.opaque_type_values
176177
},
177178
);
178179

179-
MirTypeckResults { constraints, universal_region_relations }
180+
MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
180181
}
181182

182183
fn type_check_internal<'a, 'tcx, R>(
@@ -189,7 +190,7 @@ fn type_check_internal<'a, 'tcx, R>(
189190
implicit_region_bound: ty::Region<'tcx>,
190191
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
191192
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
192-
mut extra: impl FnMut(&mut TypeChecker<'a, 'tcx>) -> R,
193+
extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
193194
) -> R {
194195
let mut checker = TypeChecker::new(
195196
infcx,
@@ -212,7 +213,7 @@ fn type_check_internal<'a, 'tcx, R>(
212213
checker.typeck_mir(body);
213214
}
214215

215-
extra(&mut checker)
216+
extra(checker)
216217
}
217218

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

804806
struct BorrowCheckContext<'a, 'tcx> {
@@ -812,6 +814,7 @@ struct BorrowCheckContext<'a, 'tcx> {
812814
crate struct MirTypeckResults<'tcx> {
813815
crate constraints: MirTypeckRegionConstraints<'tcx>,
814816
crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
817+
crate opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
815818
}
816819

817820
/// A collection of region constraints that must be satisfied for the
@@ -958,6 +961,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
958961
borrowck_context,
959962
reported_errors: Default::default(),
960963
universal_region_relations,
964+
opaque_type_values: FxHashMap::default(),
961965
};
962966
checker.check_user_type_annotations();
963967
checker
@@ -1195,6 +1199,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
11951199
let tcx = infcx.tcx;
11961200
let param_env = self.param_env;
11971201
let body = self.body;
1202+
let concrete_opaque_types = &tcx.typeck_tables_of(anon_owner_def_id).concrete_opaque_types;
1203+
let mut opaque_type_values = Vec::new();
1204+
11981205
debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id);
11991206
let opaque_type_map = self.fully_perform_op(
12001207
locations,
@@ -1226,47 +1233,65 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
12261233
);
12271234

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

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

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

1310+
self.opaque_type_values.extend(opaque_type_values);
1311+
12851312
let universal_region_relations = self.universal_region_relations;
12861313

12871314
// 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
@@ -1464,7 +1464,7 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
14641464
}
14651465
// Opaque types desugared from `impl Trait`.
14661466
ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(owner), .. }) => {
1467-
tcx.typeck_tables_of(owner)
1467+
tcx.mir_borrowck(owner)
14681468
.concrete_opaque_types
14691469
.get(&def_id)
14701470
.map(|opaque| opaque.concrete_type)
@@ -1687,7 +1687,7 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
16871687
}
16881688

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

16921692
debug!("find_opaque_ty_constraints({:?})", def_id);
16931693

@@ -1713,7 +1713,17 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
17131713
);
17141714
return;
17151715
}
1716-
let ty = self.tcx.typeck_tables_of(def_id).concrete_opaque_types.get(&self.def_id);
1716+
// Calling `mir_borrowck` can lead to cycle errors through
1717+
// const-checking, avoid calling it if we don't have to.
1718+
if !self.tcx.typeck_tables_of(def_id).concrete_opaque_types.contains_key(&self.def_id) {
1719+
debug!(
1720+
"find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`",
1721+
self.def_id, def_id,
1722+
);
1723+
return;
1724+
}
1725+
// Use borrowck to get the type with unerased regions.
1726+
let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id);
17171727
if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
17181728
debug!(
17191729
"find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}",
@@ -1856,6 +1866,13 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
18561866
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
18571867
intravisit::NestedVisitorMap::All(&self.tcx.hir())
18581868
}
1869+
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
1870+
if let hir::ExprKind::Closure(..) = ex.kind {
1871+
let def_id = self.tcx.hir().local_def_id(ex.hir_id);
1872+
self.check(def_id);
1873+
}
1874+
intravisit::walk_expr(self, ex);
1875+
}
18591876
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
18601877
debug!("find_existential_constraints: visiting {:?}", it);
18611878
let def_id = self.tcx.hir().local_def_id(it.hir_id);

0 commit comments

Comments
 (0)