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
@ -15,32 +15,40 @@
|
||||
//! handle the part about dumping the inference context internal
|
||||
//! state.
|
||||
|
||||
use rustc::ty;
|
||||
use borrow_check::nll::region_infer::RegionInferenceContext;
|
||||
use borrow_check::nll::universal_regions::DefiningTy;
|
||||
use rustc_errors::DiagnosticBuilder;
|
||||
use super::RegionInferenceContext;
|
||||
|
||||
impl<'gcx, 'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Write out our state into the `.mir` files.
|
||||
pub(crate) fn annotate(&self, err: &mut DiagnosticBuilder<'_>) {
|
||||
match self.universal_regions.defining_ty.sty {
|
||||
ty::TyClosure(def_id, substs) => {
|
||||
match self.universal_regions.defining_ty {
|
||||
DefiningTy::Closure(def_id, substs) => {
|
||||
err.note(&format!(
|
||||
"defining type: {:?} with closure substs {:#?}",
|
||||
def_id,
|
||||
&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!(
|
||||
"defining type: {:?} with substs {:#?}",
|
||||
def_id,
|
||||
&substs[..]
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
DefiningTy::Const(ty) => {
|
||||
err.note(&format!(
|
||||
"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
|
||||
//! 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::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||
use rustc::infer::region_constraints::GenericKind;
|
||||
@ -67,7 +67,7 @@ pub struct UniversalRegions<'tcx> {
|
||||
/// The "defining" type for this function, with all universal
|
||||
/// regions instantiated. For a closure or generator, this is the
|
||||
/// 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
|
||||
/// their universal `RegionVid` equivalents. This type is **NOT
|
||||
@ -96,6 +96,33 @@ pub struct UniversalRegions<'tcx> {
|
||||
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)]
|
||||
struct UniversalRegionIndices<'tcx> {
|
||||
/// 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:
|
||||
///
|
||||
/// - for functions, this is the `TyFnDef`;
|
||||
/// - 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> {
|
||||
/// Returns the "defining type" of the current MIR;
|
||||
/// see `DefiningTy` for details.
|
||||
fn defining_ty(&self) -> DefiningTy<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
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 {
|
||||
@ -514,8 +529,25 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||
tables.node_id_to_type(self.mir_hir_id)
|
||||
};
|
||||
|
||||
self.infcx
|
||||
.replace_free_regions_with_nll_infer_vars(FR, &defining_ty)
|
||||
let defining_ty = self.infcx
|
||||
.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
|
||||
@ -525,14 +557,14 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||
fn compute_indices(
|
||||
&self,
|
||||
fr_static: RegionVid,
|
||||
defining_ty: Ty<'tcx>,
|
||||
defining_ty: DefiningTy<'tcx>,
|
||||
) -> UniversalRegionIndices<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let gcx = tcx.global_tcx();
|
||||
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 fr_substs = match defining_ty.sty {
|
||||
ty::TyClosure(_, substs) | ty::TyGenerator(_, substs, ..) => {
|
||||
let fr_substs = match defining_ty {
|
||||
DefiningTy::Closure(_, substs) | DefiningTy::Generator(_, substs, _) => {
|
||||
// In the case of closures, we rely on the fact that
|
||||
// the first N elements in the ClosureSubsts are
|
||||
// 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());
|
||||
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
|
||||
// get the type `usize` here. For now, just return an
|
||||
// empty vector of substs in this case, since there are no
|
||||
// generics in scope in such expressions right now.
|
||||
//
|
||||
// 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(..) => {
|
||||
DefiningTy::Const(_) => {
|
||||
assert!(identity_substs.is_empty());
|
||||
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));
|
||||
@ -581,11 +603,11 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> {
|
||||
fn compute_inputs_and_output(
|
||||
&self,
|
||||
indices: &UniversalRegionIndices<'tcx>,
|
||||
defining_ty: Ty<'tcx>,
|
||||
defining_ty: DefiningTy<'tcx>,
|
||||
) -> ty::Binder<&'tcx ty::Slice<Ty<'tcx>>> {
|
||||
let tcx = self.infcx.tcx;
|
||||
match defining_ty.sty {
|
||||
ty::TyClosure(def_id, substs) => {
|
||||
match defining_ty {
|
||||
DefiningTy::Closure(def_id, substs) => {
|
||||
assert_eq!(self.mir_def_id, def_id);
|
||||
let closure_sig = substs.closure_sig_ty(def_id, tcx).fn_sig(tcx);
|
||||
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);
|
||||
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::TyFnDef(def_id, _) => {
|
||||
DefiningTy::FnDef(def_id, _) => {
|
||||
let sig = tcx.fn_sig(def_id);
|
||||
let sig = indices.fold_to_region_vids(tcx, &sig);
|
||||
sig.inputs_and_output()
|
||||
}
|
||||
|
||||
// FIXME: as above, this happens on things like `[foo;
|
||||
// 22]`. For now, no inputs, one output, but it seems like
|
||||
// we need a more general way to handle this category of
|
||||
// MIR.
|
||||
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
|
||||
),
|
||||
// This happens on things like `[foo; 22]`. Hence, no
|
||||
// inputs, one output, but it seems like we need a more
|
||||
// general way to handle this category of MIR.
|
||||
DefiningTy::Const(ty) => ty::Binder::dummy(tcx.mk_type_list(iter::once(ty))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -729,11 +743,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
self.tcx.fold_regions(
|
||||
value,
|
||||
&mut false,
|
||||
|_region, _depth| self.next_nll_region_var(origin),
|
||||
)
|
||||
self.tcx.fold_regions(value, &mut false, |_region, _depth| {
|
||||
self.next_nll_region_var(origin)
|
||||
})
|
||||
}
|
||||
|
||||
fn replace_bound_regions_with_nll_infer_vars<T>(
|
||||
@ -773,10 +785,8 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
tcx.fold_regions(
|
||||
value,
|
||||
&mut false,
|
||||
|region, _| tcx.mk_region(ty::ReVar(self.to_region_vid(region))),
|
||||
)
|
||||
tcx.fold_regions(value, &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…
Reference in New Issue
Block a user