mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 23:34:48 +00:00
auto merge of #11832 : jfager/rust/r5900, r=alexcrichton
I tried a couple of different ways to squash this, and still don't think this is ideal, but I wanted to get it out for feedback. Closes #5900 Closes #9942 There are a few scenarios where the compiler tries to evaluate CastExprs without the corresponding types being available yet in the type context: https://github.com/mozilla/rust/issues/10618, https://github.com/mozilla/rust/issues/5900, https://github.com/mozilla/rust/issues/9942 This PR takes the approach of having eval_const_expr_partial's CastExpr arm fall back to a limited ast_ty_to_ty call that only checks for (a subset of) valid const types, when the direct type lookup fails. It's kind of hacky, so I understand if you don't want to take this as is. I'd need a little mentoring to get this into better shape, as figuring out the proper fix has been a little daunting. I'm also happy if someone else wants to pick this up and run with it. This closes 5900 and 9942, but only moves the goalposts a little on 10618, which now falls over in a later phase of the compiler.
This commit is contained in:
commit
5a618129b8
@ -11,7 +11,9 @@
|
||||
|
||||
use metadata::csearch;
|
||||
use middle::astencode;
|
||||
|
||||
use middle::ty;
|
||||
use middle::typeck::astconv;
|
||||
use middle;
|
||||
|
||||
use syntax::{ast, ast_map, ast_util};
|
||||
@ -445,8 +447,17 @@ pub fn eval_const_expr_partial<T: ty::ExprTyProvider>(tcx: &T, e: &Expr)
|
||||
_ => Err(~"Bad operands for binary")
|
||||
}
|
||||
}
|
||||
ExprCast(base, _) => {
|
||||
let ety = tcx.expr_ty(e);
|
||||
ExprCast(base, target_ty) => {
|
||||
// This tends to get called w/o the type actually having been
|
||||
// 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.ty_ctxt(), e)
|
||||
.or_else(|| astconv::ast_ty_to_prim_ty(tcx.ty_ctxt(), target_ty))
|
||||
.unwrap_or_else(|| tcx.ty_ctxt().sess.span_fatal(
|
||||
target_ty.span,
|
||||
format!("Target type not found for const cast")
|
||||
));
|
||||
|
||||
let base = eval_const_expr_partial(tcx, base);
|
||||
match base {
|
||||
Err(_) => base,
|
||||
|
@ -2669,10 +2669,8 @@ pub fn node_id_to_trait_ref(cx: ctxt, id: ast::NodeId) -> @ty::TraitRef {
|
||||
}
|
||||
|
||||
pub fn node_id_to_type(cx: ctxt, id: ast::NodeId) -> t {
|
||||
//printfln!("{:?}/{:?}", id, cx.node_types.len());
|
||||
let node_types = cx.node_types.borrow();
|
||||
match node_types.get().find(&(id as uint)) {
|
||||
Some(&t) => t,
|
||||
match node_id_to_type_opt(cx, id) {
|
||||
Some(t) => t,
|
||||
None => cx.sess.bug(
|
||||
format!("node_id_to_type: no type for node `{}`",
|
||||
ast_map::node_id_to_str(cx.items, id,
|
||||
@ -2680,6 +2678,15 @@ pub fn node_id_to_type(cx: ctxt, id: ast::NodeId) -> t {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn node_id_to_type_opt(cx: ctxt, id: ast::NodeId) -> Option<t> {
|
||||
let node_types = cx.node_types.borrow();
|
||||
debug!("id: {:?}, node_types: {:?}", id, node_types);
|
||||
match node_types.get().find(&(id as uint)) {
|
||||
Some(&t) => Some(t),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(pcwalton): Makes a copy, bleh. Probably better to not do that.
|
||||
pub fn node_id_to_type_params(cx: ctxt, id: ast::NodeId) -> ~[t] {
|
||||
let node_type_substs = cx.node_type_substs.borrow();
|
||||
@ -2850,6 +2857,10 @@ pub fn expr_ty(cx: ctxt, expr: &ast::Expr) -> t {
|
||||
return node_id_to_type(cx, expr.id);
|
||||
}
|
||||
|
||||
pub fn expr_ty_opt(cx: ctxt, expr: &ast::Expr) -> Option<t> {
|
||||
return node_id_to_type_opt(cx, expr.id);
|
||||
}
|
||||
|
||||
pub fn expr_ty_adjusted(cx: ctxt, expr: &ast::Expr) -> t {
|
||||
/*!
|
||||
*
|
||||
|
@ -299,6 +299,74 @@ pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope>(
|
||||
pub static NO_REGIONS: uint = 1;
|
||||
pub static 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().all(|s| s.types.is_empty()) {
|
||||
tcx.sess.span_err(
|
||||
path.span,
|
||||
"type parameters are not allowed on this type");
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & NO_REGIONS) != 0u {
|
||||
if !path.segments.last().unwrap().lifetimes.is_empty() {
|
||||
tcx.sess.span_err(
|
||||
path.span,
|
||||
"region parameters are not allowed on this type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ast_ty_to_prim_ty(tcx: ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> {
|
||||
match ast_ty.node {
|
||||
ast::TyPath(ref path, _, id) => {
|
||||
let def_map = tcx.def_map.borrow();
|
||||
let a_def = match def_map.get().find(&id) {
|
||||
None => tcx.sess.span_fatal(
|
||||
ast_ty.span, format!("unbound path {}",
|
||||
path_to_str(path, tcx.sess.intr()))),
|
||||
Some(&d) => d
|
||||
};
|
||||
match a_def {
|
||||
ast::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 => {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
"bare `str` is not a type");
|
||||
// return /something/ so they can at least get more errors
|
||||
Some(ty::mk_str(tcx, ty::vstore_uniq))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
// Parses the programmer's textual representation of a type into our
|
||||
// internal notion of a type.
|
||||
pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
@ -384,26 +452,6 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
return constr(seq_ty);
|
||||
}
|
||||
|
||||
fn check_path_args(tcx: ty::ctxt,
|
||||
path: &ast::Path,
|
||||
flags: uint) {
|
||||
if (flags & NO_TPS) != 0u {
|
||||
if !path.segments.iter().all(|s| s.types.is_empty()) {
|
||||
tcx.sess.span_err(
|
||||
path.span,
|
||||
"type parameters are not allowed on this type");
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & NO_REGIONS) != 0u {
|
||||
if !path.segments.last().unwrap().lifetimes.is_empty() {
|
||||
tcx.sess.span_err(
|
||||
path.span,
|
||||
"region parameters are not allowed on this type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let tcx = this.tcx();
|
||||
|
||||
{
|
||||
@ -421,8 +469,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
ast_ty_to_ty_cache.get().insert(ast_ty.id, ty::atttce_unresolved);
|
||||
}
|
||||
|
||||
|
||||
let typ = match ast_ty.node {
|
||||
let typ = ast_ty_to_prim_ty(tcx, ast_ty).unwrap_or_else(|| match ast_ty.node {
|
||||
ast::TyNil => ty::mk_nil(),
|
||||
ast::TyBot => ty::mk_bot(),
|
||||
ast::TyBox(ty) => {
|
||||
@ -455,7 +502,8 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
}
|
||||
ast::TyBareFn(ref bf) => {
|
||||
if bf.decl.variadic && !bf.abis.is_c() {
|
||||
tcx.sess.span_err(ast_ty.span, "variadic function must have C calling convention");
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
"variadic function must have C calling convention");
|
||||
}
|
||||
ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.purity,
|
||||
bf.abis, bf.decl))
|
||||
@ -516,36 +564,6 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
ast::DefTy(did) | ast::DefStruct(did) => {
|
||||
ast_path_to_ty(this, rscope, did, path).ty
|
||||
}
|
||||
ast::DefPrimTy(nty) => {
|
||||
match nty {
|
||||
ast::TyBool => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
ty::mk_bool()
|
||||
}
|
||||
ast::TyChar => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
ty::mk_char()
|
||||
}
|
||||
ast::TyInt(it) => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
ty::mk_mach_int(it)
|
||||
}
|
||||
ast::TyUint(uit) => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
ty::mk_mach_uint(uit)
|
||||
}
|
||||
ast::TyFloat(ft) => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
ty::mk_mach_float(ft)
|
||||
}
|
||||
ast::TyStr => {
|
||||
tcx.sess.span_err(ast_ty.span,
|
||||
"bare `str` is not a type");
|
||||
// return /something/ so they can at least get more errors
|
||||
ty::mk_str(tcx, ty::vstore_uniq)
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::DefTyParam(id, n) => {
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
ty::mk_param(tcx, n, id)
|
||||
@ -564,6 +582,9 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
ast_map::node_id_to_str(tcx.items, id.node,
|
||||
token::get_ident_interner())));
|
||||
}
|
||||
ast::DefPrimTy(_) => {
|
||||
fail!("DefPrimTy arm missed in previous ast_ty_to_prim_ty call");
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.span_fatal(ast_ty.span,
|
||||
format!("found value name used as a type: {:?}", a_def));
|
||||
@ -605,7 +626,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
ast_ty.span,
|
||||
"found `ty_infer` in unexpected place");
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
let mut ast_ty_to_ty_cache = tcx.ast_ty_to_ty_cache.borrow_mut();
|
||||
ast_ty_to_ty_cache.get().insert(ast_ty.id, ty::atttce_resolved(typ));
|
||||
|
@ -4314,4 +4314,3 @@ pub fn check_intrinsic_type(ccx: @CrateCtxt, it: &ast::ForeignItem) {
|
||||
ppaux::ty_to_str(ccx.tcx, fty)));
|
||||
}
|
||||
}
|
||||
|
||||
|
21
src/test/run-pass/issue-5900.rs
Normal file
21
src/test/run-pass/issue-5900.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 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.
|
||||
|
||||
pub mod foo {
|
||||
use super::Bar;
|
||||
|
||||
pub struct FooStruct { bar : Bar }
|
||||
}
|
||||
|
||||
pub enum Bar {
|
||||
Bar0 = 0 as int
|
||||
}
|
||||
|
||||
pub fn main() {}
|
13
src/test/run-pass/issue-9942.rs
Normal file
13
src/test/run-pass/issue-9942.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 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.
|
||||
|
||||
pub fn main() {
|
||||
static S: uint = 23 as uint; [0, ..S]; ()
|
||||
}
|
Loading…
Reference in New Issue
Block a user