use collections::enum_set::{EnumSet, CLike};
use std::collections::{HashMap, HashSet};
use syntax::abi;
-use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE};
+use syntax::ast::{CrateNum, DefId, ItemTrait, LOCAL_CRATE};
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
use syntax::ast_util::{self, is_local, lit_is_str, local_def};
ty::FnDiverging => unreachable!()
}
}
+
+ pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> {
+ match self {
+ ty::FnConverging(t) => t,
+ ty::FnDiverging => def
+ }
+ }
}
pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
variant_info.arg_names.as_ref()
.expect("must have struct enum variant if accessing a named fields")
.iter().zip(variant_info.args.iter())
- .find(|&(ident, _)| ident.name == n)
- .map(|(_ident, arg_t)| arg_t.subst(cx, substs))
+ .find(|&(&name, _)| name == n)
+ .map(|(_name, arg_t)| arg_t.subst(cx, substs))
}
_ => None
}
}
}
- pub fn note_and_explain_type_err(cx: &ctxt, err: &type_err) {
+ pub fn note_and_explain_type_err<'tcx>(cx: &ctxt<'tcx>, err: &type_err<'tcx>, sp: Span) {
match *err {
terr_regions_does_not_outlive(subregion, superregion) => {
note_and_explain_region(cx, "", subregion, "...");
"expected concrete lifetime is ",
conc_region, "");
}
+ terr_sorts(values) => {
+ let expected_str = ty_sort_string(cx, values.expected);
+ let found_str = ty_sort_string(cx, values.found);
+ if expected_str == found_str && expected_str == "closure" {
+ cx.sess.span_note(sp, &format!("no two closures, even if identical, have the same \
+ type"));
+ cx.sess.span_help(sp, &format!("consider boxing your closure and/or \
+ using it as a trait object"));
+ }
+ }
_ => {}
}
}
#[derive(Clone)]
pub struct VariantInfo<'tcx> {
pub args: Vec<Ty<'tcx>>,
- pub arg_names: Option<Vec<ast::Ident>>,
+ pub arg_names: Option<Vec<ast::Name>>,
pub ctor_ty: Option<Ty<'tcx>>,
pub name: ast::Name,
pub id: ast::DefId,
.map(|field| node_id_to_type(cx, field.node.id)).collect();
let arg_names = fields.iter().map(|field| {
match field.node.kind {
- NamedField(ident, _) => ident,
+ NamedField(ident, _) => ident.name,
UnnamedField(..) => cx.sess.bug(
"enum_variants: all fields in struct must have a name")
}
pub working_dir: PathBuf,
pub lint_store: RefCell<lint::LintStore>,
pub lints: RefCell<NodeMap<Vec<(lint::LintId, codemap::Span, String)>>>,
+ pub plugin_llvm_passes: RefCell<Vec<String>>,
pub crate_types: RefCell<Vec<config::CrateType>>,
pub crate_metadata: RefCell<Vec<String>>,
pub features: RefCell<feature_gate::Features>,
if self.opts.treat_err_as_bug {
self.span_bug(sp, msg);
}
- self.diagnostic().span_fatal(sp, msg)
+ panic!(self.diagnostic().span_fatal(sp, msg))
}
pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! {
if self.opts.treat_err_as_bug {
self.span_bug(sp, msg);
}
- self.diagnostic().span_fatal_with_code(sp, msg, code)
+ panic!(self.diagnostic().span_fatal_with_code(sp, msg, code))
}
pub fn fatal(&self, msg: &str) -> ! {
if self.opts.treat_err_as_bug {
pub fn span_end_note(&self, sp: Span, msg: &str) {
self.diagnostic().span_end_note(sp, msg)
}
+
+ /// Prints out a message with a suggested edit of the code.
+ ///
+ /// See `diagnostic::RenderSpan::Suggestion` for more information.
+ pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) {
+ self.diagnostic().span_suggestion(sp, msg, suggestion)
+ }
pub fn span_help(&self, sp: Span, msg: &str) {
self.diagnostic().span_help(sp, msg)
}
self.diagnostic().handler().note(msg)
}
pub fn help(&self, msg: &str) {
- self.diagnostic().handler().note(msg)
+ self.diagnostic().handler().help(msg)
}
pub fn opt_span_bug(&self, opt_sp: Option<Span>, msg: &str) -> ! {
match opt_sp {
working_dir: env::current_dir().unwrap(),
lint_store: RefCell::new(lint::LintStore::new()),
lints: RefCell::new(NodeMap()),
+ plugin_llvm_passes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
crate_metadata: RefCell::new(Vec::new()),
features: RefCell::new(feature_gate::Features::new()),
pub mod method;
mod upvar;
pub mod wf;
+mod cast;
mod closure;
mod callee;
mod compare_method;
// back and process them.
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'tcx>>>>,
- deferred_cast_checks: RefCell<Vec<CastCheck<'tcx>>>,
+ deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
}
trait DeferredCallResolution<'tcx> {
type DeferredCallResolutionHandler<'tcx> = Box<DeferredCallResolution<'tcx>+'tcx>;
-/// Reifies a cast check to be checked once we have full type information for
-/// a function context.
-struct CastCheck<'tcx> {
- expr: ast::Expr,
- expr_ty: Ty<'tcx>,
- cast_ty: Ty<'tcx>,
- span: Span,
-}
-
/// When type-checking an expression, we propagate downward
/// whatever type hint we are able in the form of an `Expectation`.
#[derive(Copy, Clone)]
}
-fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
- fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- span: Span,
- t_1: Ty<'tcx>,
- t_e: Ty<'tcx>) {
- fcx.type_error_message(span, |actual| {
- format!("illegal cast; cast through an \
- integer first: `{}` as `{}`",
- actual,
- fcx.infcx().ty_to_string(t_1))
- }, t_e, None);
- }
-
- let span = cast.span;
- let e = &cast.expr;
- let t_e = structurally_resolved_type(fcx, span, cast.expr_ty);
- let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty);
-
- // Check for trivial casts.
- if !ty::type_has_ty_infer(t_1) {
- if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) {
- if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) {
- fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
- e.id,
- span,
- format!("trivial numeric cast: `{}` as `{}`. Cast can be \
- replaced by coercion, this might require type \
- ascription or a temporary variable",
- fcx.infcx().ty_to_string(t_e),
- fcx.infcx().ty_to_string(t_1)));
- } else {
- fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS,
- e.id,
- span,
- format!("trivial cast: `{}` as `{}`. Cast can be \
- replaced by coercion, this might require type \
- ascription or a temporary variable",
- fcx.infcx().ty_to_string(t_e),
- fcx.infcx().ty_to_string(t_1)));
- }
- return;
- }
- }
-
- let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e);
- let t_e_is_scalar = ty::type_is_scalar(t_e);
- let t_e_is_integral = ty::type_is_integral(t_e);
- let t_e_is_float = ty::type_is_floating_point(t_e);
- let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e);
-
- let t_1_is_scalar = ty::type_is_scalar(t_1);
- let t_1_is_char = ty::type_is_char(t_1);
- let t_1_is_bare_fn = ty::type_is_bare_fn(t_1);
- let t_1_is_float = ty::type_is_floating_point(t_1);
-
- // casts to scalars other than `char` and `bare fn` are trivial
- let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
-
- if t_e_is_bare_fn_item && t_1_is_bare_fn {
- demand::coerce(fcx, e.span, t_1, &e);
- } else if t_1_is_char {
- let t_e = fcx.infcx().shallow_resolve(t_e);
- if t_e.sty != ty::ty_uint(ast::TyU8) {
- fcx.type_error_message(span, |actual| {
- format!("only `u8` can be cast as `char`, not `{}`", actual)
- }, t_e, None);
- }
- } else if t_1.sty == ty::ty_bool {
- span_err!(fcx.tcx().sess, span, E0054,
- "cannot cast as `bool`, compare with zero instead");
- } else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && !(
- t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) {
- // Casts to float must go through an integer or boolean
- cast_through_integer_err(fcx, span, t_1, t_e)
- } else if t_e_is_c_enum && t_1_is_trivial {
- if ty::type_is_unsafe_ptr(t_1) {
- // ... and likewise with C enum -> *T
- cast_through_integer_err(fcx, span, t_1, t_e)
- }
- // casts from C-like enums are allowed
- } else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) {
- fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
- t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool {
- match t1.sty {
- ty::ty_vec(_, Some(_)) => {}
- _ => return false
- }
- if ty::type_needs_infer(t2) {
- // This prevents this special case from going off when casting
- // to a type that isn't fully specified; e.g. `as *_`. (Issue
- // #14893.)
- return false
- }
-
- let el = ty::sequence_element_type(fcx.tcx(), t1);
- infer::mk_eqty(fcx.infcx(),
- false,
- infer::Misc(sp),
- el,
- t2).is_ok()
- }
-
- // Due to the limitations of LLVM global constants,
- // region pointers end up pointing at copies of
- // vector elements instead of the original values.
- // To allow unsafe pointers to work correctly, we
- // need to special-case obtaining an unsafe pointer
- // from a region pointer to a vector.
-
- /* this cast is only allowed from &[T, ..n] to *T or
- &T to *T. */
- match (&t_e.sty, &t_1.sty) {
- (&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }),
- &ty::ty_ptr(ty::mt { ty: mt2, mutbl: ast::MutImmutable }))
- if types_compatible(fcx, e.span, mt1, mt2) => {
- /* this case is allowed */
- }
- _ => {
- demand::coerce(fcx, e.span, t_1, &e);
- }
- }
- } else if !(t_e_is_scalar && t_1_is_trivial) {
- /*
- If more type combinations should be supported than are
- supported here, then file an enhancement issue and
- record the issue number in this comment.
- */
- fcx.type_error_message(span, |actual| {
- format!("non-scalar cast: `{}` as `{}`",
- actual,
- fcx.infcx().ty_to_string(t_1))
- }, t_e, None);
- }
-}
-
impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx }
span)
}
+ pub fn type_is_fat_ptr(&self, ty: Ty<'tcx>, span: Span) -> bool {
+ if let Some(mt) = ty::deref(ty, true) {
+ return !self.type_is_known_to_be_sized(mt.ty, span);
+ }
+ false
+ }
+
pub fn register_builtin_bound(&self,
ty: Ty<'tcx>,
builtin_bound: ty::BuiltinBound,
fn check_casts(&self) {
let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
for check in deferred_cast_checks.iter() {
- check_cast(self, check);
+ cast::check_cast(self, check);
}
deferred_cast_checks.clear();
let def = path_res.base_def;
if path_res.depth == 0 {
- let (scheme, predicates) =
- type_scheme_and_predicates_for_def(fcx, expr.span, def);
- instantiate_path(fcx, &path.segments,
- scheme, &predicates,
- opt_self_ty, def, expr.span, id);
+ let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx,
+ expr.span,
+ def);
+ instantiate_path(fcx,
+ &path.segments,
+ scheme,
+ &predicates,
+ opt_self_ty,
+ def,
+ expr.span,
+ id);
} else {
let ty_segments = path.segments.init();
let base_ty_end = path.segments.len() - path_res.depth;
// Defer other checks until we're done type checking.
let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
- deferred_cast_checks.push(CastCheck {
- expr: (**e).clone(),
- expr_ty: t_e,
- cast_ty: t_1,
- span: expr.span,
- });
+ let cast_check = cast::CastCheck::new((**e).clone(), t_e, t_1, expr.span);
+ deferred_cast_checks.push(cast_check);
}
}
ast::ExprVec(ref args) => {
.ty_to_string(
actual_structure_type),
type_error_description);
- ty::note_and_explain_type_err(tcx, &type_error);
+ ty::note_and_explain_type_err(tcx, &type_error, path.span);
}
}
}
"assume" => (0, vec![tcx.types.bool], ty::mk_nil(tcx)),
+ "discriminant_value" => (1, vec![
+ ty::mk_imm_rptr(tcx,
+ tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
+ ty::BrAnon(0))),
+ param(ccx, 0))], tcx.types.u64),
+
ref other => {
span_err!(tcx.sess, it.span, E0093,
"unrecognized intrinsic function: `{}`", *other);