Prepare to use borrowck to resolve opaque types
This commit is contained in:
parent
43a3348fd9
commit
75ac0cca36
@ -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};
|
||||
@ -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]>,
|
||||
}
|
||||
|
@ -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.
|
||||
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
@ -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>,
|
||||
@ -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");
|
||||
@ -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,
|
||||
|
@ -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,
|
||||
@ -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>(
|
||||
@ -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,
|
||||
@ -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<'_, '_>) {
|
||||
@ -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> {
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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,
|
||||
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
@ -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)
|
||||
@ -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);
|
||||
|
||||
@ -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 `{:?}`: {:?}",
|
||||
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user