get the DefiningTy
from the body_owner_kind
not type
The type isn't a good idea because we want to treat constants uniformly, regardless of what type of value they produce.
This commit is contained in:
parent
0e64a756f8
commit
fe89f4ba86
3 changed files with 112 additions and 73 deletions
|
@ -15,32 +15,40 @@
|
||||||
//! handle the part about dumping the inference context internal
|
//! handle the part about dumping the inference context internal
|
||||||
//! state.
|
//! state.
|
||||||
|
|
||||||
use rustc::ty;
|
use borrow_check::nll::region_infer::RegionInferenceContext;
|
||||||
|
use borrow_check::nll::universal_regions::DefiningTy;
|
||||||
use rustc_errors::DiagnosticBuilder;
|
use rustc_errors::DiagnosticBuilder;
|
||||||
use super::RegionInferenceContext;
|
|
||||||
|
|
||||||
impl<'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
impl<'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
||||||
/// Write out our state into the `.mir` files.
|
/// Write out our state into the `.mir` files.
|
||||||
pub(crate) fn annotate(&self, err: &mut DiagnosticBuilder<'_>) {
|
pub(crate) fn annotate(&self, err: &mut DiagnosticBuilder<'_>) {
|
||||||
match self.universal_regions.defining_ty.sty {
|
match self.universal_regions.defining_ty {
|
||||||
ty::TyClosure(def_id, substs) => {
|
DefiningTy::Closure(def_id, substs) => {
|
||||||
err.note(&format!(
|
err.note(&format!(
|
||||||
"defining type: {:?} with closure substs {:#?}",
|
"defining type: {:?} with closure substs {:#?}",
|
||||||
def_id,
|
def_id,
|
||||||
&substs.substs[..]
|
&substs.substs[..]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ty::TyFnDef(def_id, substs) => {
|
DefiningTy::Generator(def_id, substs, interior) => {
|
||||||
|
err.note(&format!(
|
||||||
|
"defining type: {:?} with closure substs {:#?} and interior {:?}",
|
||||||
|
def_id,
|
||||||
|
&substs.substs[..],
|
||||||
|
interior
|
||||||
|
));
|
||||||
|
}
|
||||||
|
DefiningTy::FnDef(def_id, substs) => {
|
||||||
err.note(&format!(
|
err.note(&format!(
|
||||||
"defining type: {:?} with substs {:#?}",
|
"defining type: {:?} with substs {:#?}",
|
||||||
def_id,
|
def_id,
|
||||||
&substs[..]
|
&substs[..]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
_ => {
|
DefiningTy::Const(ty) => {
|
||||||
err.note(&format!(
|
err.note(&format!(
|
||||||
"defining type: {:?}",
|
"defining type: {:?}",
|
||||||
self.universal_regions.defining_ty
|
ty
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
//! The code in this file doesn't *do anything* with those results; it
|
//! The code in this file doesn't *do anything* with those results; it
|
||||||
//! just returns them for other code to use.
|
//! just returns them for other code to use.
|
||||||
|
|
||||||
use rustc::hir::HirId;
|
use rustc::hir::{BodyOwnerKind, HirId};
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||||
use rustc::infer::region_constraints::GenericKind;
|
use rustc::infer::region_constraints::GenericKind;
|
||||||
|
@ -67,7 +67,7 @@ pub struct UniversalRegions<'tcx> {
|
||||||
/// The "defining" type for this function, with all universal
|
/// The "defining" type for this function, with all universal
|
||||||
/// regions instantiated. For a closure or generator, this is the
|
/// regions instantiated. For a closure or generator, this is the
|
||||||
/// closure type, but for a top-level function it's the `TyFnDef`.
|
/// closure type, but for a top-level function it's the `TyFnDef`.
|
||||||
pub defining_ty: Ty<'tcx>,
|
pub defining_ty: DefiningTy<'tcx>,
|
||||||
|
|
||||||
/// The return type of this function, with all regions replaced by
|
/// The return type of this function, with all regions replaced by
|
||||||
/// their universal `RegionVid` equivalents. This type is **NOT
|
/// their universal `RegionVid` equivalents. This type is **NOT
|
||||||
|
@ -96,6 +96,33 @@ pub struct UniversalRegions<'tcx> {
|
||||||
relations: UniversalRegionRelations,
|
relations: UniversalRegionRelations,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The "defining type" for this MIR. The key feature of the "defining
|
||||||
|
/// type" is that it contains the information needed to derive all the
|
||||||
|
/// universal regions that are in scope as well as the types of the
|
||||||
|
/// inputs/output from the MIR. In general, early-bound universal
|
||||||
|
/// regions appear free in the defining type and late-bound regions
|
||||||
|
/// appear bound in the signature.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum DefiningTy<'tcx> {
|
||||||
|
/// The MIR is a closure. The signature is found via
|
||||||
|
/// `ClosureSubsts::closure_sig_ty`.
|
||||||
|
Closure(DefId, ty::ClosureSubsts<'tcx>),
|
||||||
|
|
||||||
|
/// The MIR is a generator. The signature is that generators take
|
||||||
|
/// no parameters and return the result of
|
||||||
|
/// `ClosureSubsts::generator_return_ty`.
|
||||||
|
Generator(DefId, ty::ClosureSubsts<'tcx>, ty::GeneratorInterior<'tcx>),
|
||||||
|
|
||||||
|
/// The MIR is a fn item with the given def-id and substs. The signature
|
||||||
|
/// of the function can be bound then with the `fn_sig` query.
|
||||||
|
FnDef(DefId, &'tcx Substs<'tcx>),
|
||||||
|
|
||||||
|
/// The MIR represents some form of constant. The signature then
|
||||||
|
/// is that it has no inputs and a single return value, which is
|
||||||
|
/// the value of the constant.
|
||||||
|
Const(Ty<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct UniversalRegionIndices<'tcx> {
|
struct UniversalRegionIndices<'tcx> {
|
||||||
/// For those regions that may appear in the parameter environment
|
/// For those regions that may appear in the parameter environment
|
||||||
|
@ -488,23 +515,11 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the "defining type" of the current MIR:
|
/// Returns the "defining type" of the current MIR;
|
||||||
///
|
/// see `DefiningTy` for details.
|
||||||
/// - for functions, this is the `TyFnDef`;
|
fn defining_ty(&self) -> DefiningTy<'tcx> {
|
||||||
/// - for closures, this is the `TyClosure`;
|
|
||||||
/// - for generators, this is the `TyGenerator`;
|
|
||||||
/// - for constants, this is the type of value that gets produced.
|
|
||||||
/// - FIXME. Constants are handled somewhat inelegantly; this gets
|
|
||||||
/// patched in a later PR that has already landed on nll-master.
|
|
||||||
///
|
|
||||||
/// The key feature of the "defining type" is that it contains the
|
|
||||||
/// information needed to derive all the universal regions that
|
|
||||||
/// are in scope as well as the types of the inputs/output from
|
|
||||||
/// the MIR. In general, early-bound universal regions appear free
|
|
||||||
/// in the defining type and late-bound regions appear bound in
|
|
||||||
/// the signature.
|
|
||||||
fn defining_ty(&self) -> ty::Ty<'tcx> {
|
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
|
|
||||||
let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
|
let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
|
||||||
|
|
||||||
let defining_ty = if self.mir_def_id == closure_base_def_id {
|
let defining_ty = if self.mir_def_id == closure_base_def_id {
|
||||||
|
@ -514,8 +529,25 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||||
tables.node_id_to_type(self.mir_hir_id)
|
tables.node_id_to_type(self.mir_hir_id)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.infcx
|
let defining_ty = self.infcx
|
||||||
.replace_free_regions_with_nll_infer_vars(FR, &defining_ty)
|
.replace_free_regions_with_nll_infer_vars(FR, &defining_ty);
|
||||||
|
|
||||||
|
match tcx.hir.body_owner_kind(self.mir_node_id) {
|
||||||
|
BodyOwnerKind::Fn => match defining_ty.sty {
|
||||||
|
ty::TyClosure(def_id, substs) => DefiningTy::Closure(def_id, substs),
|
||||||
|
ty::TyGenerator(def_id, substs, interior) => {
|
||||||
|
DefiningTy::Generator(def_id, substs, interior)
|
||||||
|
}
|
||||||
|
ty::TyFnDef(def_id, substs) => DefiningTy::FnDef(def_id, substs),
|
||||||
|
_ => span_bug!(
|
||||||
|
tcx.def_span(self.mir_def_id),
|
||||||
|
"expected defining type for `{:?}`: `{:?}`",
|
||||||
|
self.mir_def_id,
|
||||||
|
defining_ty
|
||||||
|
),
|
||||||
|
},
|
||||||
|
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => DefiningTy::Const(defining_ty),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a hashmap that maps from the universal regions that are
|
/// Builds a hashmap that maps from the universal regions that are
|
||||||
|
@ -525,14 +557,14 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||||
fn compute_indices(
|
fn compute_indices(
|
||||||
&self,
|
&self,
|
||||||
fr_static: RegionVid,
|
fr_static: RegionVid,
|
||||||
defining_ty: Ty<'tcx>,
|
defining_ty: DefiningTy<'tcx>,
|
||||||
) -> UniversalRegionIndices<'tcx> {
|
) -> UniversalRegionIndices<'tcx> {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let gcx = tcx.global_tcx();
|
let gcx = tcx.global_tcx();
|
||||||
let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
|
let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
|
||||||
let identity_substs = Substs::identity_for_item(gcx, closure_base_def_id);
|
let identity_substs = Substs::identity_for_item(gcx, closure_base_def_id);
|
||||||
let fr_substs = match defining_ty.sty {
|
let fr_substs = match defining_ty {
|
||||||
ty::TyClosure(_, substs) | ty::TyGenerator(_, substs, ..) => {
|
DefiningTy::Closure(_, substs) | DefiningTy::Generator(_, substs, _) => {
|
||||||
// In the case of closures, we rely on the fact that
|
// In the case of closures, we rely on the fact that
|
||||||
// the first N elements in the ClosureSubsts are
|
// the first N elements in the ClosureSubsts are
|
||||||
// inherited from the `closure_base_def_id`.
|
// inherited from the `closure_base_def_id`.
|
||||||
|
@ -544,28 +576,18 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||||
assert_eq!(substs.substs.regions().count(), identity_substs.regions().count());
|
assert_eq!(substs.substs.regions().count(), identity_substs.regions().count());
|
||||||
substs.substs
|
substs.substs
|
||||||
}
|
}
|
||||||
ty::TyFnDef(_, substs) => substs,
|
|
||||||
|
|
||||||
// FIXME. When we encounter other sorts of constant
|
DefiningTy::FnDef(_, substs) => substs,
|
||||||
|
|
||||||
|
// When we encounter other sorts of constant
|
||||||
// expressions, such as the `22` in `[foo; 22]`, we can
|
// expressions, such as the `22` in `[foo; 22]`, we can
|
||||||
// get the type `usize` here. For now, just return an
|
// get the type `usize` here. For now, just return an
|
||||||
// empty vector of substs in this case, since there are no
|
// empty vector of substs in this case, since there are no
|
||||||
// generics in scope in such expressions right now.
|
// generics in scope in such expressions right now.
|
||||||
//
|
DefiningTy::Const(_) => {
|
||||||
// Eventually I imagine we could get a wider range of
|
|
||||||
// types. What is the best way to handle this? Should we
|
|
||||||
// be checking something other than the type of the def-id
|
|
||||||
// to figure out what to do (e.g. the def-key?).
|
|
||||||
ty::TyUint(..) => {
|
|
||||||
assert!(identity_substs.is_empty());
|
assert!(identity_substs.is_empty());
|
||||||
identity_substs
|
identity_substs
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => span_bug!(
|
|
||||||
tcx.def_span(self.mir_def_id),
|
|
||||||
"unknown defining type: {:?}",
|
|
||||||
defining_ty
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let global_mapping = iter::once((gcx.types.re_static, fr_static));
|
let global_mapping = iter::once((gcx.types.re_static, fr_static));
|
||||||
|
@ -581,11 +603,11 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||||
fn compute_inputs_and_output(
|
fn compute_inputs_and_output(
|
||||||
&self,
|
&self,
|
||||||
indices: &UniversalRegionIndices<'tcx>,
|
indices: &UniversalRegionIndices<'tcx>,
|
||||||
defining_ty: Ty<'tcx>,
|
defining_ty: DefiningTy<'tcx>,
|
||||||
) -> ty::Binder<&'tcx ty::Slice<Ty<'tcx>>> {
|
) -> ty::Binder<&'tcx ty::Slice<Ty<'tcx>>> {
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
match defining_ty.sty {
|
match defining_ty {
|
||||||
ty::TyClosure(def_id, substs) => {
|
DefiningTy::Closure(def_id, substs) => {
|
||||||
assert_eq!(self.mir_def_id, def_id);
|
assert_eq!(self.mir_def_id, def_id);
|
||||||
let closure_sig = substs.closure_sig_ty(def_id, tcx).fn_sig(tcx);
|
let closure_sig = substs.closure_sig_ty(def_id, tcx).fn_sig(tcx);
|
||||||
let inputs_and_output = closure_sig.inputs_and_output();
|
let inputs_and_output = closure_sig.inputs_and_output();
|
||||||
|
@ -613,32 +635,24 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyGenerator(def_id, substs, ..) => {
|
DefiningTy::Generator(def_id, substs, interior) => {
|
||||||
assert_eq!(self.mir_def_id, def_id);
|
assert_eq!(self.mir_def_id, def_id);
|
||||||
let output = substs.generator_return_ty(def_id, tcx);
|
let output = substs.generator_return_ty(def_id, tcx);
|
||||||
let inputs_and_output = self.infcx.tcx.intern_type_list(&[defining_ty, output]);
|
let generator_ty = tcx.mk_generator(def_id, substs, interior);
|
||||||
|
let inputs_and_output = self.infcx.tcx.intern_type_list(&[generator_ty, output]);
|
||||||
ty::Binder::dummy(inputs_and_output)
|
ty::Binder::dummy(inputs_and_output)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyFnDef(def_id, _) => {
|
DefiningTy::FnDef(def_id, _) => {
|
||||||
let sig = tcx.fn_sig(def_id);
|
let sig = tcx.fn_sig(def_id);
|
||||||
let sig = indices.fold_to_region_vids(tcx, &sig);
|
let sig = indices.fold_to_region_vids(tcx, &sig);
|
||||||
sig.inputs_and_output()
|
sig.inputs_and_output()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: as above, this happens on things like `[foo;
|
// This happens on things like `[foo; 22]`. Hence, no
|
||||||
// 22]`. For now, no inputs, one output, but it seems like
|
// inputs, one output, but it seems like we need a more
|
||||||
// we need a more general way to handle this category of
|
// general way to handle this category of MIR.
|
||||||
// MIR.
|
DefiningTy::Const(ty) => ty::Binder::dummy(tcx.mk_type_list(iter::once(ty))),
|
||||||
ty::TyUint(..) => {
|
|
||||||
ty::Binder::dummy(tcx.mk_type_list(iter::once(defining_ty)))
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => span_bug!(
|
|
||||||
tcx.def_span(self.mir_def_id),
|
|
||||||
"unexpected defining type: {:?}",
|
|
||||||
defining_ty
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,11 +743,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> {
|
||||||
where
|
where
|
||||||
T: TypeFoldable<'tcx>,
|
T: TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
self.tcx.fold_regions(
|
self.tcx.fold_regions(value, &mut false, |_region, _depth| {
|
||||||
value,
|
self.next_nll_region_var(origin)
|
||||||
&mut false,
|
})
|
||||||
|_region, _depth| self.next_nll_region_var(origin),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_bound_regions_with_nll_infer_vars<T>(
|
fn replace_bound_regions_with_nll_infer_vars<T>(
|
||||||
|
@ -773,10 +785,8 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
|
||||||
where
|
where
|
||||||
T: TypeFoldable<'tcx>,
|
T: TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
tcx.fold_regions(
|
tcx.fold_regions(value, &mut false, |region, _| {
|
||||||
value,
|
tcx.mk_region(ty::ReVar(self.to_region_vid(region)))
|
||||||
&mut false,
|
})
|
||||||
|region, _| tcx.mk_region(ty::ReVar(self.to_region_vid(region))),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
21
src/test/ui/nll/constant.rs
Normal file
21
src/test/ui/nll/constant.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that MIR borrowck and NLL analysis can handle constants of
|
||||||
|
// arbitrary types without ICEs.
|
||||||
|
|
||||||
|
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||||
|
// must-compile-successfully
|
||||||
|
|
||||||
|
const HI: &str = "hi";
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(HI, "hi");
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue