Remove one dependence on typeck from const_eval.

This commit is contained in:
Niko Matsakis 2014-11-26 04:52:02 -05:00
parent 00ca861f9d
commit 55470abe72
5 changed files with 119 additions and 99 deletions

View File

@ -59,6 +59,7 @@ pub mod back {
}
pub mod middle {
pub mod astconv_util;
pub mod astencode;
pub mod borrowck;
pub mod cfg;

View File

@ -0,0 +1,89 @@
// Copyright 2012-2014 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.
/*!
* This module contains a simple utility routine
* used by both `typeck` and `const_eval`.
* Almost certainly this could (and should) be refactored out of existence.
*/
use middle::def;
use middle::ty::{mod, Ty};
use syntax::ast;
use util::ppaux::Repr;
pub const NO_REGIONS: uint = 1;
pub const NO_TPS: uint = 2;
pub fn check_path_args(tcx: &ty::ctxt,
path: &ast::Path,
flags: uint) {
if (flags & NO_TPS) != 0u {
if path.segments.iter().any(|s| s.parameters.has_types()) {
span_err!(tcx.sess, path.span, E0109,
"type parameters are not allowed on this type");
}
}
if (flags & NO_REGIONS) != 0u {
if path.segments.iter().any(|s| s.parameters.has_lifetimes()) {
span_err!(tcx.sess, path.span, E0110,
"region parameters are not allowed on this type");
}
}
}
pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
-> Option<Ty<'tcx>> {
match ast_ty.node {
ast::TyPath(ref path, id) => {
let a_def = match tcx.def_map.borrow().get(&id) {
None => {
tcx.sess.span_bug(ast_ty.span,
format!("unbound path {}",
path.repr(tcx)).as_slice())
}
Some(&d) => d
};
match a_def {
def::DefPrimTy(nty) => {
match nty {
ast::TyBool => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
Some(ty::mk_bool())
}
ast::TyChar => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
Some(ty::mk_char())
}
ast::TyInt(it) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
Some(ty::mk_mach_int(it))
}
ast::TyUint(uit) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
Some(ty::mk_mach_uint(uit))
}
ast::TyFloat(ft) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
Some(ty::mk_mach_float(ft))
}
ast::TyStr => {
Some(ty::mk_str(tcx))
}
}
}
_ => None
}
}
_ => None
}
}

View File

@ -17,8 +17,8 @@ pub use self::constness::*;
use metadata::csearch;
use middle::{astencode, def};
use middle::pat_util::def_to_path;
use middle::ty::{mod, Ty};
use middle::typeck::{astconv, check};
use middle::ty::{mod};
use middle::astconv_util::{ast_ty_to_prim_ty};
use util::nodemap::DefIdMap;
use syntax::ast::{mod, Expr};
@ -277,14 +277,6 @@ impl<'a, 'tcx> ConstEvalVisitor<'a, 'tcx> {
}
impl<'a, 'tcx, 'v> Visitor<'v> for ConstEvalVisitor<'a, 'tcx> {
fn visit_ty(&mut self, t: &ast::Ty) {
if let ast::TyFixedLengthVec(_, ref expr) = t.node {
check::check_const_in_type(self.tcx, &**expr, ty::mk_uint());
}
visit::walk_ty(self, t);
}
fn visit_expr_post(&mut self, e: &Expr) {
self.classify(e);
}
@ -504,7 +496,7 @@ pub fn eval_const_expr_partial(tcx: &ty::ctxt, e: &Expr) -> Result<const_val, St
// populated in the ctxt, which was causing things to blow up
// (#5900). Fall back to doing a limited lookup to get past it.
let ety = ty::expr_ty_opt(tcx, e)
.or_else(|| astconv::ast_ty_to_prim_ty(tcx, &**target_ty))
.or_else(|| ast_ty_to_prim_ty(tcx, &**target_ty))
.unwrap_or_else(|| {
tcx.sess.span_fatal(target_ty.span,
"target type not found for const cast")

View File

@ -46,6 +46,8 @@
//! Note that the self region for the `foo` defaulted to `&` in the first
//! case but `&a` in the second. Basically, defaults that appear inside
//! an rptr (`&r.T`) use the region `r` that appears in the rptr.
use middle::astconv_util::{ast_ty_to_prim_ty, check_path_args, NO_TPS, NO_REGIONS};
use middle::const_eval;
use middle::def;
use middle::resolve_lifetime as rl;
@ -553,74 +555,6 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
}
}
pub const NO_REGIONS: uint = 1;
pub const NO_TPS: uint = 2;
fn check_path_args(tcx: &ty::ctxt,
path: &ast::Path,
flags: uint) {
if (flags & NO_TPS) != 0u {
if path.segments.iter().any(|s| s.parameters.has_types()) {
span_err!(tcx.sess, path.span, E0109,
"type parameters are not allowed on this type");
}
}
if (flags & NO_REGIONS) != 0u {
if path.segments.iter().any(|s| s.parameters.has_lifetimes()) {
span_err!(tcx.sess, path.span, E0110,
"region parameters are not allowed on this type");
}
}
}
pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
-> Option<Ty<'tcx>> {
match ast_ty.node {
ast::TyPath(ref path, id) => {
let a_def = match tcx.def_map.borrow().get(&id) {
None => {
tcx.sess.span_bug(ast_ty.span,
format!("unbound path {}",
path.repr(tcx)).as_slice())
}
Some(&d) => d
};
match a_def {
def::DefPrimTy(nty) => {
match nty {
ast::TyBool => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
Some(ty::mk_bool())
}
ast::TyChar => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
Some(ty::mk_char())
}
ast::TyInt(it) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
Some(ty::mk_mach_int(it))
}
ast::TyUint(uit) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
Some(ty::mk_mach_uint(uit))
}
ast::TyFloat(ft) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
Some(ty::mk_mach_float(ft))
}
ast::TyStr => {
Some(ty::mk_str(tcx))
}
}
}
_ => None
}
}
_ => None
}
}
/// Converts the given AST type to a built-in type. A "built-in type" is, at
/// present, either a core numeric type, a string, or `Box`.
pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(

View File

@ -361,6 +361,17 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckItemTypesVisitor<'a, 'tcx> {
check_item(self.ccx, i);
visit::walk_item(self, i);
}
fn visit_ty(&mut self, t: &ast::Ty) {
match t.node {
ast::TyFixedLengthVec(_, ref expr) => {
check_const_in_type(self.ccx, &**expr, ty::mk_uint());
}
_ => {}
}
visit::walk_ty(self, t);
}
}
pub fn check_item_types(ccx: &CrateCtxt) {
@ -4672,25 +4683,18 @@ fn check_block_with_expected<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
/// Checks a constant appearing in a type. At the moment this is just the
/// length expression in a fixed-length vector, but someday it might be
/// extended to type-level numeric literals.
pub fn check_const_in_type<'tcx>(tcx: &ty::ctxt<'tcx>,
expr: &ast::Expr,
expected_type: Ty<'tcx>) {
// Synthesize a crate context. The trait map is not needed here (though I
// imagine it will be if we have associated statics --pcwalton), so we
// leave it blank.
let ccx = CrateCtxt {
trait_map: NodeMap::new(),
tcx: tcx,
};
let inh = static_inherited_fields(&ccx);
let fcx = blank_fn_ctxt(&ccx, &inh, ty::FnConverging(expected_type), expr.id);
fn check_const_in_type<'a,'tcx>(ccx: &'a CrateCtxt<'a,'tcx>,
expr: &ast::Expr,
expected_type: Ty<'tcx>) {
let inh = static_inherited_fields(ccx);
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(expected_type), expr.id);
check_const_with_ty(&fcx, expr.span, expr, expected_type);
}
pub fn check_const(ccx: &CrateCtxt,
sp: Span,
e: &ast::Expr,
id: ast::NodeId) {
fn check_const(ccx: &CrateCtxt,
sp: Span,
e: &ast::Expr,
id: ast::NodeId) {
let inh = static_inherited_fields(ccx);
let rty = ty::node_id_to_type(ccx.tcx, id);
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id);
@ -4698,10 +4702,10 @@ pub fn check_const(ccx: &CrateCtxt,
check_const_with_ty(&fcx, sp, e, declty);
}
pub fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
_: Span,
e: &ast::Expr,
declty: Ty<'tcx>) {
fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
_: Span,
e: &ast::Expr,
declty: Ty<'tcx>) {
// Gather locals in statics (because of block expressions).
// This is technically unnecessary because locals in static items are forbidden,
// but prevents type checking from blowing up before const checking can properly