Skip to content

Commit

Permalink
Prepare to use borrowck to resolve opaque types
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewjasper committed Feb 14, 2020
1 parent 43a3348 commit 75ac0cc
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 68 deletions.
8 changes: 7 additions & 1 deletion src/librustc/mir/query.rs
@@ -1,8 +1,10 @@
//! Values computed by queries that use MIR.

use crate::ty::{self, Ty};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitMatrix;
use rustc_index::vec::IndexVec;
use rustc_span::{Span, Symbol};
Expand Down Expand Up @@ -59,8 +61,12 @@ pub struct GeneratorLayout<'tcx> {
pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
}

#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
#[derive(Debug, RustcEncodable, RustcDecodable, HashStable)]
pub struct BorrowCheckResult<'tcx> {
/// All the opaque types that are restricted to concrete types
/// by this function. Unlike the value in `TypeckTables`, this has
/// unerased regions.
pub concrete_opaque_types: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
pub used_mut_upvars: SmallVec<[Field; 8]>,
}
Expand Down
32 changes: 19 additions & 13 deletions src/librustc_mir/borrow_check/mod.rs
Expand Up @@ -195,19 +195,24 @@ fn do_mir_borrowck<'a, 'tcx>(
Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));

// Compute non-lexical lifetimes.
let nll::NllOutput { regioncx, polonius_output, opt_closure_req, nll_errors } =
nll::compute_regions(
infcx,
def_id,
free_regions,
body,
&promoted,
location_table,
param_env,
&mut flow_inits,
&mdpe.move_data,
&borrow_set,
);
let nll::NllOutput {
regioncx,
opaque_type_values,
polonius_output,
opt_closure_req,
nll_errors,
} = nll::compute_regions(
infcx,
def_id,
free_regions,
body,
&promoted,
location_table,
param_env,
&mut flow_inits,
&mdpe.move_data,
&borrow_set,
);

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

let result = BorrowCheckResult {
concrete_opaque_types: opaque_type_values,
closure_requirements: opt_closure_req,
used_mut_upvars: mbcx.used_mut_upvars,
};
Expand Down
32 changes: 18 additions & 14 deletions src/librustc_mir/borrow_check/nll.rs
Expand Up @@ -6,6 +6,7 @@ use rustc::mir::{
Location, Promoted, ReadOnlyBodyAndCache,
};
use rustc::ty::{self, RegionKind, RegionVid};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::DefId;
use rustc_index::vec::IndexVec;
Expand Down Expand Up @@ -46,6 +47,7 @@ crate type PoloniusOutput = Output<RustcFacts>;
/// closure requirements to propagate, and any generated errors.
crate struct NllOutput<'tcx> {
pub regioncx: RegionInferenceContext<'tcx>,
pub opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
pub polonius_output: Option<Rc<PoloniusOutput>>,
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
pub nll_errors: RegionErrors<'tcx>,
Expand Down Expand Up @@ -160,20 +162,21 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
let elements = &Rc::new(RegionValueElements::new(&body));

// Run the MIR type-checker.
let MirTypeckResults { constraints, universal_region_relations } = type_check::type_check(
infcx,
param_env,
body,
promoted,
def_id,
&universal_regions,
location_table,
borrow_set,
&mut all_facts,
flow_inits,
move_data,
elements,
);
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
type_check::type_check(
infcx,
param_env,
body,
promoted,
def_id,
&universal_regions,
location_table,
borrow_set,
&mut all_facts,
flow_inits,
move_data,
elements,
);

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

NllOutput {
regioncx,
opaque_type_values,
polonius_output,
opt_closure_req: closure_region_requirements,
nll_errors,
Expand Down
101 changes: 64 additions & 37 deletions src/librustc_mir/borrow_check/type_check/mod.rs
Expand Up @@ -158,7 +158,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
constraints: &mut constraints,
};

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

translate_outlives_facts(&mut cx);
cx.opaque_type_values
},
);

MirTypeckResults { constraints, universal_region_relations }
MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
}

fn type_check_internal<'a, 'tcx, R>(
Expand All @@ -189,7 +190,7 @@ fn type_check_internal<'a, 'tcx, R>(
implicit_region_bound: ty::Region<'tcx>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
mut extra: impl FnMut(&mut TypeChecker<'a, 'tcx>) -> R,
extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
) -> R {
let mut checker = TypeChecker::new(
infcx,
Expand All @@ -212,7 +213,7 @@ fn type_check_internal<'a, 'tcx, R>(
checker.typeck_mir(body);
}

extra(&mut checker)
extra(checker)
}

fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
Expand Down Expand Up @@ -799,6 +800,7 @@ struct TypeChecker<'a, 'tcx> {
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
}

struct BorrowCheckContext<'a, 'tcx> {
Expand All @@ -812,6 +814,7 @@ struct BorrowCheckContext<'a, 'tcx> {
crate struct MirTypeckResults<'tcx> {
crate constraints: MirTypeckRegionConstraints<'tcx>,
crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
crate opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
}

/// A collection of region constraints that must be satisfied for the
Expand Down Expand Up @@ -958,6 +961,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
borrowck_context,
reported_errors: Default::default(),
universal_region_relations,
opaque_type_values: FxHashMap::default(),
};
checker.check_user_type_annotations();
checker
Expand Down Expand Up @@ -1195,6 +1199,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let tcx = infcx.tcx;
let param_env = self.param_env;
let body = self.body;
let concrete_opaque_types = &tcx.typeck_tables_of(anon_owner_def_id).concrete_opaque_types;
let mut opaque_type_values = Vec::new();

debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id);
let opaque_type_map = self.fully_perform_op(
locations,
Expand Down Expand Up @@ -1226,47 +1233,65 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);

for (&opaque_def_id, opaque_decl) in &opaque_type_map {
let opaque_defn_ty = tcx.type_of(opaque_def_id);
let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
let opaque_defn_ty = renumber::renumber_regions(infcx, &opaque_defn_ty);
let concrete_is_opaque = infcx
.resolve_vars_if_possible(&opaque_decl.concrete_ty)
.is_impl_trait();
let resolved_ty = infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty);
let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind {
def_id == opaque_def_id
} else {
false
};
let opaque_defn_ty = match concrete_opaque_types.get(&opaque_def_id) {
None => {
assert!(
concrete_is_opaque,
"Non-defining use of {:?} with revealed type",
opaque_def_id,
);
continue;
}
Some(opaque_defn_ty) => opaque_defn_ty,
};
debug!("opaque_defn_ty = {:?}", opaque_defn_ty);
let subst_opaque_defn_ty =
opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs);
let renumbered_opaque_defn_ty =
renumber::renumber_regions(infcx, &subst_opaque_defn_ty);

debug!(
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?} \
concrete_is_opaque={}",
opaque_decl.concrete_ty,
infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty),
opaque_defn_ty,
concrete_is_opaque
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
opaque_decl.concrete_ty, resolved_ty, renumbered_opaque_defn_ty,
);

// concrete_is_opaque is `true` when we're using an opaque `impl Trait`
// type without 'revealing' it. For example, code like this:
//
// type Foo = impl Debug;
// fn foo1() -> Foo { ... }
// fn foo2() -> Foo { foo1() }
//
// In `foo2`, we're not revealing the type of `Foo` - we're
// just treating it as the opaque type.
//
// When this occurs, we do *not* want to try to equate
// the concrete type with the underlying defining type
// of the opaque type - this will always fail, since
// the defining type of an opaque type is always
// some other type (e.g. not itself)
// Essentially, none of the normal obligations apply here -
// we're just passing around some unknown opaque type,
// without actually looking at the underlying type it
// gets 'revealed' into

if !concrete_is_opaque {
obligations.add(
infcx
.at(&ObligationCause::dummy(), param_env)
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?,
.eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?,
);
opaque_type_values
.push((opaque_def_id, ty::ResolvedOpaqueTy { ..*opaque_defn_ty }));
} else {
// We're using an opaque `impl Trait` type without
// 'revealing' it. For example, code like this:
//
// type Foo = impl Debug;
// fn foo1() -> Foo { ... }
// fn foo2() -> Foo { foo1() }
//
// In `foo2`, we're not revealing the type of `Foo` - we're
// just treating it as the opaque type.
//
// When this occurs, we do *not* want to try to equate
// the concrete type with the underlying defining type
// of the opaque type - this will always fail, since
// the defining type of an opaque type is always
// some other type (e.g. not itself)
// Essentially, none of the normal obligations apply here -
// we're just passing around some unknown opaque type,
// without actually looking at the underlying type it
// gets 'revealed' into
debug!(
"eq_opaque_type_and_type: non-defining use of {:?}",
opaque_def_id,
);
}
}
Expand All @@ -1282,6 +1307,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
),
)?;

self.opaque_type_values.extend(opaque_type_values);

let universal_region_relations = self.universal_region_relations;

// Finally, if we instantiated the anon types successfully, we
Expand Down
23 changes: 20 additions & 3 deletions src/librustc_typeck/collect.rs
Expand Up @@ -1464,7 +1464,7 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(owner), .. }) => {
tcx.typeck_tables_of(owner)
tcx.mir_borrowck(owner)
.concrete_opaque_types
.get(&def_id)
.map(|opaque| opaque.concrete_type)
Expand Down Expand Up @@ -1687,7 +1687,7 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
}

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

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

Expand All @@ -1713,7 +1713,17 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
);
return;
}
let ty = self.tcx.typeck_tables_of(def_id).concrete_opaque_types.get(&self.def_id);
// Calling `mir_borrowck` can lead to cycle errors through
// const-checking, avoid calling it if we don't have to.
if !self.tcx.typeck_tables_of(def_id).concrete_opaque_types.contains_key(&self.def_id) {
debug!(
"find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`",
self.def_id, def_id,
);
return;
}
// Use borrowck to get the type with unerased regions.
let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id);
if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
debug!(
"find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}",
Expand Down Expand Up @@ -1856,6 +1866,13 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
intravisit::NestedVisitorMap::All(&self.tcx.hir())
}
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
if let hir::ExprKind::Closure(..) = ex.kind {
let def_id = self.tcx.hir().local_def_id(ex.hir_id);
self.check(def_id);
}
intravisit::walk_expr(self, ex);
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
debug!("find_existential_constraints: visiting {:?}", it);
let def_id = self.tcx.hir().local_def_id(it.hir_id);
Expand Down

0 comments on commit 75ac0cc

Please sign in to comment.