Skip to content

Commit 19288dd

Browse files
committed
Auto merge of #67681 - matthewjasper:infer-regions-in-borrowck, r=nikomatsakis
Infer regions for opaque types in borrowck This is a step towards the goal of typeck not doing region inference. The commits up to `Arena allocate the result of mir_borrowck` are various bug fixes and prerequisites. The remaining commits move opaque type inference to borrow checking. r? @nikomatsakis
2 parents b92c6ee + d863978 commit 19288dd

File tree

72 files changed

+1996
-1304
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1996
-1304
lines changed

Diff for: src/librustc/arena.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ macro_rules! arena_types {
3535
rustc::mir::Promoted,
3636
rustc::mir::BodyAndCache<$tcx>
3737
>,
38-
[] tables: rustc::ty::TypeckTables<$tcx>,
38+
[decode] tables: rustc::ty::TypeckTables<$tcx>,
39+
[decode] borrowck_result: rustc::mir::BorrowCheckResult<$tcx>,
3940
[] const_allocs: rustc::mir::interpret::Allocation,
4041
[] vtable_method: Option<(
4142
rustc_hir::def_id::DefId,

Diff for: src/librustc/infer/error_reporting/mod.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -405,17 +405,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
405405
}
406406

407407
RegionResolutionError::MemberConstraintFailure {
408-
opaque_type_def_id,
409408
hidden_ty,
410409
member_region,
411-
span: _,
412-
choice_regions: _,
410+
span,
413411
} => {
414412
let hidden_ty = self.resolve_vars_if_possible(&hidden_ty);
415413
opaque_types::unexpected_hidden_region_diagnostic(
416414
self.tcx,
417415
Some(region_scope_tree),
418-
opaque_type_def_id,
416+
span,
419417
hidden_ty,
420418
member_region,
421419
)

Diff for: src/librustc/infer/lexical_region_resolve/mod.rs

+1-10
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use rustc_data_structures::fx::FxHashSet;
1818
use rustc_data_structures::graph::implementation::{
1919
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
2020
};
21-
use rustc_hir::def_id::DefId;
2221
use rustc_index::vec::{Idx, IndexVec};
2322
use rustc_span::Span;
2423
use std::fmt;
@@ -95,13 +94,7 @@ pub enum RegionResolutionError<'tcx> {
9594
/// Indicates a failure of a `MemberConstraint`. These arise during
9695
/// impl trait processing explicitly -- basically, the impl trait's hidden type
9796
/// included some region that it was not supposed to.
98-
MemberConstraintFailure {
99-
span: Span,
100-
opaque_type_def_id: DefId,
101-
hidden_ty: Ty<'tcx>,
102-
member_region: Region<'tcx>,
103-
choice_regions: Vec<Region<'tcx>>,
104-
},
97+
MemberConstraintFailure { span: Span, hidden_ty: Ty<'tcx>, member_region: Region<'tcx> },
10598
}
10699

107100
struct RegionAndOrigin<'tcx> {
@@ -656,10 +649,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
656649
let span = self.tcx().def_span(member_constraint.opaque_type_def_id);
657650
errors.push(RegionResolutionError::MemberConstraintFailure {
658651
span,
659-
opaque_type_def_id: member_constraint.opaque_type_def_id,
660652
hidden_ty: member_constraint.hidden_ty,
661653
member_region,
662-
choice_regions: choice_regions.collect(),
663654
});
664655
}
665656
}

Diff for: src/librustc/infer/opaque_types/mod.rs

+85-47
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ pub struct OpaqueTypeDecl<'tcx> {
9393
pub origin: hir::OpaqueTyOrigin,
9494
}
9595

96+
/// Whether member constraints should be generated for all opaque types
97+
pub enum GenerateMemberConstraints {
98+
/// The default, used by typeck
99+
WhenRequired,
100+
/// The borrow checker needs member constraints in any case where we don't
101+
/// have a `'static` bound. This is because the borrow checker has more
102+
/// flexibility in the values of regions. For example, given `f<'a, 'b>`
103+
/// the borrow checker can have an inference variable outlive `'a` and `'b`,
104+
/// but not be equal to `'static`.
105+
IfNoStaticBound,
106+
}
107+
96108
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
97109
/// Replaces all opaque types in `value` with fresh inference variables
98110
/// and creates appropriate obligations. For example, given the input:
@@ -315,7 +327,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
315327
debug!("constrain_opaque_types()");
316328

317329
for (&def_id, opaque_defn) in opaque_types {
318-
self.constrain_opaque_type(def_id, opaque_defn, free_region_relations);
330+
self.constrain_opaque_type(
331+
def_id,
332+
opaque_defn,
333+
GenerateMemberConstraints::WhenRequired,
334+
free_region_relations,
335+
);
319336
}
320337
}
321338

@@ -324,6 +341,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
324341
&self,
325342
def_id: DefId,
326343
opaque_defn: &OpaqueTypeDecl<'tcx>,
344+
mode: GenerateMemberConstraints,
327345
free_region_relations: &FRR,
328346
) {
329347
debug!("constrain_opaque_type()");
@@ -358,6 +376,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
358376
op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
359377
});
360378
}
379+
if let GenerateMemberConstraints::IfNoStaticBound = mode {
380+
self.generate_member_constraint(
381+
concrete_ty,
382+
opaque_type_generics,
383+
opaque_defn,
384+
def_id,
385+
);
386+
}
361387
return;
362388
}
363389

@@ -398,13 +424,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
398424
// we will create a "in bound" like `'r in
399425
// ['a, 'b, 'c]`, where `'a..'c` are the
400426
// regions that appear in the impl trait.
427+
428+
// For now, enforce a feature gate outside of async functions.
429+
self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_arg);
430+
401431
return self.generate_member_constraint(
402432
concrete_ty,
403433
opaque_type_generics,
404434
opaque_defn,
405435
def_id,
406-
lr,
407-
subst_arg,
408436
);
409437
}
410438
}
@@ -414,6 +442,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
414442
let least_region = least_region.unwrap_or(tcx.lifetimes.re_static);
415443
debug!("constrain_opaque_types: least_region={:?}", least_region);
416444

445+
if let GenerateMemberConstraints::IfNoStaticBound = mode {
446+
if least_region != tcx.lifetimes.re_static {
447+
self.generate_member_constraint(
448+
concrete_ty,
449+
opaque_type_generics,
450+
opaque_defn,
451+
def_id,
452+
);
453+
}
454+
}
417455
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
418456
tcx: self.tcx,
419457
op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
@@ -434,19 +472,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
434472
opaque_type_generics: &ty::Generics,
435473
opaque_defn: &OpaqueTypeDecl<'tcx>,
436474
opaque_type_def_id: DefId,
437-
conflict1: ty::Region<'tcx>,
438-
conflict2: ty::Region<'tcx>,
439475
) {
440-
// For now, enforce a feature gate outside of async functions.
441-
if self.member_constraint_feature_gate(
442-
opaque_defn,
443-
opaque_type_def_id,
444-
conflict1,
445-
conflict2,
446-
) {
447-
return;
448-
}
449-
450476
// Create the set of choice regions: each region in the hidden
451477
// type can be equal to any of the region parameters of the
452478
// opaque type definition.
@@ -500,8 +526,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
500526
hir::OpaqueTyOrigin::AsyncFn => return false,
501527

502528
// Otherwise, generate the label we'll use in the error message.
503-
hir::OpaqueTyOrigin::TypeAlias => "impl Trait",
504-
hir::OpaqueTyOrigin::FnReturn => "impl Trait",
529+
hir::OpaqueTyOrigin::TypeAlias
530+
| hir::OpaqueTyOrigin::FnReturn
531+
| hir::OpaqueTyOrigin::Misc => "impl Trait",
505532
};
506533
let msg = format!("ambiguous lifetime bound in `{}`", context_name);
507534
let mut err = self.tcx.sess.struct_span_err(span, &msg);
@@ -549,13 +576,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
549576
/// # Parameters
550577
///
551578
/// - `def_id`, the `impl Trait` type
552-
/// - `opaque_defn`, the opaque definition created in `instantiate_opaque_types`
579+
/// - `substs`, the substs used to instantiate this opaque type
553580
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
554581
/// `opaque_defn.concrete_ty`
555582
pub fn infer_opaque_definition_from_instantiation(
556583
&self,
557584
def_id: DefId,
558-
opaque_defn: &OpaqueTypeDecl<'tcx>,
585+
substs: SubstsRef<'tcx>,
559586
instantiated_ty: Ty<'tcx>,
560587
span: Span,
561588
) -> Ty<'tcx> {
@@ -571,12 +598,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
571598
// `impl Trait` return type, resulting in the parameters
572599
// shifting.
573600
let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
574-
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = opaque_defn
575-
.substs
576-
.iter()
577-
.enumerate()
578-
.map(|(index, subst)| (*subst, id_substs[index]))
579-
.collect();
601+
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
602+
substs.iter().enumerate().map(|(index, subst)| (*subst, id_substs[index])).collect();
580603

581604
// Convert the type from the function into a type valid outside
582605
// the function, by replacing invalid regions with 'static,
@@ -598,11 +621,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
598621
pub fn unexpected_hidden_region_diagnostic(
599622
tcx: TyCtxt<'tcx>,
600623
region_scope_tree: Option<&region::ScopeTree>,
601-
opaque_type_def_id: DefId,
624+
span: Span,
602625
hidden_ty: Ty<'tcx>,
603626
hidden_region: ty::Region<'tcx>,
604627
) -> DiagnosticBuilder<'tcx> {
605-
let span = tcx.def_span(opaque_type_def_id);
606628
let mut err = struct_span_err!(
607629
tcx.sess,
608630
span,
@@ -817,32 +839,48 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
817839

818840
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
819841
match r {
820-
// ignore bound regions that appear in the type (e.g., this
821-
// would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
822-
ty::ReLateBound(..) |
823-
824-
// ignore `'static`, as that can appear anywhere
825-
ty::ReStatic => return r,
826-
827-
_ => { }
842+
// Ignore bound regions and `'static` regions that appear in the
843+
// type, we only need to remap regions that reference lifetimes
844+
// from the function declaraion.
845+
// This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
846+
ty::ReLateBound(..) | ty::ReStatic => return r,
847+
848+
// If regions have been erased (by writeback), don't try to unerase
849+
// them.
850+
ty::ReErased => return r,
851+
852+
// The regions that we expect from borrow checking.
853+
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
854+
855+
ty::ReEmpty(_)
856+
| ty::RePlaceholder(_)
857+
| ty::ReVar(_)
858+
| ty::ReScope(_)
859+
| ty::ReClosureBound(_) => {
860+
// All of the regions in the type should either have been
861+
// erased by writeback, or mapped back to named regions by
862+
// borrow checking.
863+
bug!("unexpected region kind in opaque type: {:?}", r);
864+
}
828865
}
829866

830867
let generics = self.tcx().generics_of(self.opaque_type_def_id);
831868
match self.map.get(&r.into()).map(|k| k.unpack()) {
832869
Some(GenericArgKind::Lifetime(r1)) => r1,
833870
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
871+
None if self.map_missing_regions_to_empty || self.tainted_by_errors => {
872+
self.tcx.lifetimes.re_root_empty
873+
}
834874
None if generics.parent.is_some() => {
835-
if !self.map_missing_regions_to_empty && !self.tainted_by_errors {
836-
if let Some(hidden_ty) = self.hidden_ty.take() {
837-
unexpected_hidden_region_diagnostic(
838-
self.tcx,
839-
None,
840-
self.opaque_type_def_id,
841-
hidden_ty,
842-
r,
843-
)
844-
.emit();
845-
}
875+
if let Some(hidden_ty) = self.hidden_ty.take() {
876+
unexpected_hidden_region_diagnostic(
877+
self.tcx,
878+
None,
879+
self.tcx.def_span(self.opaque_type_def_id),
880+
hidden_ty,
881+
r,
882+
)
883+
.emit();
846884
}
847885
self.tcx.lifetimes.re_root_empty
848886
}
@@ -860,7 +898,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
860898
)
861899
.emit();
862900

863-
self.tcx().mk_region(ty::ReStatic)
901+
self.tcx().lifetimes.re_static
864902
}
865903
}
866904
}

Diff for: src/librustc/mir/query.rs

+7-1
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
}

Diff for: src/librustc/query/mod.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ rustc_queries! {
125125

126126
/// Fetch the MIR for a given `DefId` right after it's built - this includes
127127
/// unreachable code.
128-
query mir_built(_: DefId) -> &'tcx Steal<mir::BodyAndCache<'tcx>> {}
128+
query mir_built(_: DefId) -> &'tcx Steal<mir::BodyAndCache<'tcx>> {
129+
desc { "building MIR for" }
130+
}
129131

130132
/// Fetch the MIR for a given `DefId` up till the point where it is
131133
/// ready for const evaluation.
@@ -345,6 +347,7 @@ rustc_queries! {
345347
TypeChecking {
346348
/// The result of unsafety-checking this `DefId`.
347349
query unsafety_check_result(key: DefId) -> mir::UnsafetyCheckResult {
350+
desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
348351
cache_on_disk_if { key.is_local() }
349352
}
350353

@@ -414,14 +417,8 @@ rustc_queries! {
414417
}
415418

416419
query typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> {
420+
desc { |tcx| "type-checking `{}`", tcx.def_path_str(key) }
417421
cache_on_disk_if { key.is_local() }
418-
load_cached(tcx, id) {
419-
let typeck_tables: Option<ty::TypeckTables<'tcx>> = tcx
420-
.queries.on_disk_cache
421-
.try_load_query_result(tcx, id);
422-
423-
typeck_tables.map(|tables| &*tcx.arena.alloc(tables))
424-
}
425422
}
426423
query diagnostic_only_typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> {
427424
cache_on_disk_if { key.is_local() }
@@ -452,8 +449,13 @@ rustc_queries! {
452449
BorrowChecking {
453450
/// Borrow-checks the function body. If this is a closure, returns
454451
/// additional requirements that the closure's creator must verify.
455-
query mir_borrowck(key: DefId) -> mir::BorrowCheckResult<'tcx> {
456-
cache_on_disk_if(tcx, _) { key.is_local() && tcx.is_closure(key) }
452+
query mir_borrowck(key: DefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
453+
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) }
454+
cache_on_disk_if(tcx, opt_result) {
455+
key.is_local()
456+
&& (tcx.is_closure(key)
457+
|| opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty()))
458+
}
457459
}
458460
}
459461

Diff for: src/librustc/ty/flags.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl FlagComputation {
138138
}
139139

140140
&ty::Opaque(_, substs) => {
141-
self.add_flags(TypeFlags::HAS_PROJECTION);
141+
self.add_flags(TypeFlags::HAS_PROJECTION | TypeFlags::HAS_TY_OPAQUE);
142142
self.add_substs(substs);
143143
}
144144

0 commit comments

Comments
 (0)