|
#![feature(no_std, prelude_import)] |
|
#![no_std] |
|
// Copyright 2012-2013 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. |
|
|
|
//! The Rust compiler. |
|
//! |
|
//! # Note |
|
//! |
|
//! This API is completely unstable and subject to change. |
|
|
|
// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) |
|
#![feature(custom_attribute)] |
|
#![crate_name = "rustc"] |
|
#![unstable(feature = "rustc_private", issue = "27812")] |
|
#![staged_api] |
|
#![crate_type = "dylib"] |
|
#![crate_type = "rlib"] |
|
#![doc(html_logo_url = |
|
"https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", |
|
html_favicon_url = "https://doc.rust-lang.org/favicon.ico", |
|
html_root_url = "https://doc.rust-lang.org/nightly/")] |
|
|
|
#![feature(associated_consts)] |
|
#![feature(box_patterns)] |
|
#![feature(box_syntax)] |
|
#![feature(cell_extras)] |
|
#![feature(clone_from_slice)] |
|
#![feature(collections)] |
|
#![feature(const_fn)] |
|
#![feature(enumset)] |
|
#![feature(hashmap_hasher)] |
|
#![feature(into_cow)] |
|
#![feature(iter_arith)] |
|
#![feature(libc)] |
|
#![feature(nonzero)] |
|
#![feature(num_bits_bytes)] |
|
#![feature(quote)] |
|
#![feature(rustc_diagnostic_macros)] |
|
#![feature(rustc_private)] |
|
#![feature(scoped_tls)] |
|
#![feature(slice_patterns)] |
|
#![feature(staged_api)] |
|
#![feature(str_char)] |
|
#![feature(time2)] |
|
#![feature(wrapping)] |
|
|
|
#![allow(trivial_casts)] |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
#[macro_use] |
|
extern crate std as std; |
|
|
|
extern crate arena; |
|
extern crate core; |
|
extern crate flate; |
|
extern crate fmt_macros; |
|
extern crate getopts; |
|
extern crate graphviz; |
|
extern crate libc; |
|
extern crate rustc_llvm; |
|
extern crate rustc_back; |
|
extern crate rustc_front; |
|
extern crate rustc_data_structures; |
|
extern crate serialize; |
|
extern crate collections; |
|
#[macro_use] |
|
extern crate log; |
|
#[macro_use] |
|
extern crate syntax; |
|
#[macro_use] |
|
#[no_link] |
|
extern crate rustc_bitflags; |
|
|
|
extern crate serialize as rustc_serialize; |
|
// used by deriving |
|
|
|
|
|
pub use rustc_llvm as llvm; |
|
|
|
#[macro_use] |
|
mod macros { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
|
|
// NB: This module needs to be declared first so diagnostics are |
|
// registered before they are used. |
|
pub mod diagnostics { |
|
|
|
|
|
|
|
// STAGE0: increase glitch immunity |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// A private module so that macro-expanded idents like |
|
// `::rustc::lint::Lint` will also work in `rustc` itself. |
|
// |
|
// `libstd` uses the same trick. |
|
|
|
// FIXME(#27438): right now the unit tests of librustc don't refer to any actual |
|
// functions generated in librustc_data_structures (all |
|
// references are through generic functions), but statics are |
|
// referenced from time to time. Due to this bug we won't |
|
// actually correctly link in the statics unless we also |
|
// reference a function, so be sure to reference a dummy |
|
// function. |
|
|
|
|
|
// Build the diagnostics array at the end so that the metadata includes error use sites. |
|
#![allow(non_snake_case)] |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
mod __register_diagnostic_E0001 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0002 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0003 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0004 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0005 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0007 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0008 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0009 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0010 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0011 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0013 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0014 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0015 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0016 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0017 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0018 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0019 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0020 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0022 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0030 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0038 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0109 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0110 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0133 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0136 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0137 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0138 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0139 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0152 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0158 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0161 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0162 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0165 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0170 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0261 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0262 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0263 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0265 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0267 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0268 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0269 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0270 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0271 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0272 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0273 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0274 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0275 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0276 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0277 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0281 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0282 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0296 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0297 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0301 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0302 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0303 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0306 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0307 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0308 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0309 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0310 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0378 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0394 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0395 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0396 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0397 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0398 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0400 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0492 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0493 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0494 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0496 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0497 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0517 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0518 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0229 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0264 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0278 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0279 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0280 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0283 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0284 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0285 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0298 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0299 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0300 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0304 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0305 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0311 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0312 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0313 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0314 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0315 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0316 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0452 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0453 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0471 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0472 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0473 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0474 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0475 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0476 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0477 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0478 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0479 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0480 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0481 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0482 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0483 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0484 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0485 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0486 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0487 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0488 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0489 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0490 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0491 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
mod __register_diagnostic_E0495 { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
} |
|
} |
|
pub mod back { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
pub use rustc_back::abi; |
|
pub use rustc_back::rpath; |
|
pub use rustc_back::svh; |
|
} |
|
pub mod front { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
pub mod check_attr { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
use session::Session; |
|
use syntax::ast; |
|
use syntax::attr::AttrMetaMethods; |
|
use syntax::visit; |
|
use syntax::visit::Visitor; |
|
enum Target { Fn, Struct, Enum, Other, } |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for Target { |
|
#[inline] |
|
fn eq(&self, __arg_0: &Target) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&Target::Fn, &Target::Fn) => true, |
|
(&Target::Struct, &Target::Struct) => true, |
|
(&Target::Enum, &Target::Enum) => true, |
|
(&Target::Other, &Target::Other) => true, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &Target) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&Target::Fn, &Target::Fn) => false, |
|
(&Target::Struct, &Target::Struct) => false, |
|
(&Target::Enum, &Target::Enum) => false, |
|
(&Target::Other, &Target::Other) => false, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for Target { |
|
#[inline] |
|
fn clone(&self) -> Target { |
|
match (&*self,) { |
|
(&Target::Fn,) => Target::Fn, |
|
(&Target::Struct,) => Target::Struct, |
|
(&Target::Enum,) => Target::Enum, |
|
(&Target::Other,) => Target::Other, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for Target { } |
|
impl Target { |
|
fn from_item(item: &ast::Item) -> Target { |
|
match item.node { |
|
ast::ItemFn(..) => Target::Fn, |
|
ast::ItemStruct(..) => Target::Struct, |
|
ast::ItemEnum(..) => Target::Enum, |
|
_ => Target::Other, |
|
} |
|
} |
|
} |
|
struct CheckAttrVisitor<'a> { |
|
sess: &'a Session, |
|
} |
|
impl <'a> CheckAttrVisitor<'a> { |
|
fn check_inline(&self, attr: &ast::Attribute, target: Target) { |
|
if target != Target::Fn { |
|
{ |
|
(); |
|
self.sess.span_err_with_code(attr.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["attribute should be applied to function"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0518") |
|
}; |
|
} |
|
} |
|
fn check_repr(&self, attr: &ast::Attribute, target: Target) { |
|
let words = |
|
match attr.meta_item_list() { |
|
Some(words) => words, |
|
None => { return; } |
|
}; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(words) { |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(word) => { |
|
let word: &str = &word.name(); |
|
let message = |
|
match word { |
|
"C" => { |
|
if target != |
|
Target::Struct && |
|
target != |
|
Target::Enum { |
|
"attribute should be applied to struct or enum" |
|
} else { continue } |
|
} |
|
"packed" | "simd" => { |
|
if target != |
|
Target::Struct { |
|
"attribute should be applied to struct" |
|
} else { continue } |
|
} |
|
"i8" | "u8" | "i16" | "u16" | |
|
"i32" | "u32" | "i64" | "u64" |
|
| "isize" | "usize" => { |
|
if target != Target::Enum |
|
{ |
|
"attribute should be applied to enum" |
|
} else { continue } |
|
} |
|
_ => continue , |
|
}; |
|
{ |
|
(); |
|
self.sess.span_err_with_code(attr.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&[""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&message,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0517") |
|
}; |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
fn check_attribute(&self, attr: &ast::Attribute, target: Target) { |
|
let name: &str = &attr.name(); |
|
match name { |
|
"inline" => self.check_inline(attr, target), |
|
"repr" => self.check_repr(attr, target), |
|
_ => (), |
|
} |
|
} |
|
} |
|
impl <'a, 'v> Visitor<'v> for CheckAttrVisitor<'a> { |
|
fn visit_item(&mut self, item: &ast::Item) { |
|
let target = Target::from_item(item); |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&item.attrs) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(attr) => { |
|
self.check_attribute(attr, target); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
} |
|
pub fn check_crate(sess: &Session, krate: &ast::Crate) { |
|
visit::walk_crate(&mut CheckAttrVisitor{sess: sess,}, krate); |
|
} |
|
} |
|
pub mod map { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
pub use self::Node::*; |
|
pub use self::PathElem::*; |
|
use self::MapEntry::*; |
|
use self::collector::NodeCollector; |
|
pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, |
|
DisambiguatedDefPathData}; |
|
use middle::cstore::InlinedItem; |
|
use middle::cstore::InlinedItem as II; |
|
use middle::def_id::DefId; |
|
use syntax::abi; |
|
use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID}; |
|
use syntax::codemap::{Span, Spanned}; |
|
use syntax::parse::token; |
|
use rustc_front::hir::*; |
|
use rustc_front::fold::Folder; |
|
use rustc_front::intravisit; |
|
use rustc_front::print::pprust; |
|
use arena::TypedArena; |
|
use std::cell::RefCell; |
|
use std::fmt; |
|
use std::io; |
|
use std::iter; |
|
use std::mem; |
|
use std::slice; |
|
pub mod blocks { |
|
//! This module provides a simplified abstraction for working with |
|
//! code blocks identified by their integer node-id. In particular, |
|
//! it captures a common set of attributes that all "function-like |
|
//! things" (represented by `FnLike` instances) share. For example, |
|
//! all `FnLike` instances have a type signature (be it explicit or |
|
//! inferred). And all `FnLike` instances have a body, i.e. the code |
|
//! that is run when the function-like thing it represents is invoked. |
|
//! |
|
//! With the above abstraction in place, one can treat the program |
|
//! text as a collection of blocks of code (and most such blocks are |
|
//! nested within a uniquely determined `FnLike`), and users can ask |
|
//! for the `Code` associated with a particular NodeId. |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
pub use self::Code::*; |
|
use front::map::{self, Node}; |
|
use syntax::abi; |
|
use rustc_front::hir::{Block, FnDecl}; |
|
use syntax::ast::{Name, NodeId}; |
|
use rustc_front::hir as ast; |
|
use syntax::codemap::Span; |
|
use rustc_front::intravisit::FnKind; |
|
/// An FnLikeNode is a Node that is like a fn, in that it has a decl |
|
/// and a body (as well as a NodeId, a span, etc). |
|
/// |
|
/// More specifically, it is one of either: |
|
/// - A function item, |
|
/// - A closure expr (i.e. an ExprClosure), or |
|
/// - The default implementation for a trait method. |
|
/// |
|
/// To construct one, use the `Code::from_node` function. |
|
pub struct FnLikeNode<'a> { |
|
node: map::Node<'a>, |
|
} |
|
#[automatically_derived] |
|
impl <'a> ::std::clone::Clone for FnLikeNode<'a> { |
|
#[inline] |
|
fn clone(&self) -> FnLikeNode<'a> { |
|
match *self { |
|
FnLikeNode { node: ref __self_0_0 } => |
|
FnLikeNode{node: |
|
::std::clone::Clone::clone(&(*__self_0_0)),}, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl <'a> ::std::marker::Copy for FnLikeNode<'a> { } |
|
/// MaybeFnLike wraps a method that indicates if an object |
|
/// corresponds to some FnLikeNode. |
|
pub trait MaybeFnLike { |
|
fn is_fn_like(&self) |
|
-> bool; |
|
} |
|
/// Components shared by fn-like things (fn items, methods, closures). |
|
pub struct FnParts<'a> { |
|
pub decl: &'a FnDecl, |
|
pub body: &'a Block, |
|
pub kind: FnKind<'a>, |
|
pub span: Span, |
|
pub id: NodeId, |
|
} |
|
impl MaybeFnLike for ast::Item { |
|
fn is_fn_like(&self) -> bool { |
|
match self.node { ast::ItemFn(..) => true, _ => false, } |
|
} |
|
} |
|
impl MaybeFnLike for ast::TraitItem { |
|
fn is_fn_like(&self) -> bool { |
|
match self.node { |
|
ast::MethodTraitItem(_, Some(_)) => true, |
|
_ => false, |
|
} |
|
} |
|
} |
|
impl MaybeFnLike for ast::Expr { |
|
fn is_fn_like(&self) -> bool { |
|
match self.node { |
|
ast::ExprClosure(..) => true, |
|
_ => false, |
|
} |
|
} |
|
} |
|
/// Carries either an FnLikeNode or a Block, as these are the two |
|
/// constructs that correspond to "code" (as in, something from which |
|
/// we can construct a control-flow graph). |
|
pub enum Code<'a> { |
|
FnLikeCode(FnLikeNode<'a>), |
|
BlockCode(&'a Block), |
|
} |
|
#[automatically_derived] |
|
impl <'a> ::std::clone::Clone for Code<'a> { |
|
#[inline] |
|
fn clone(&self) -> Code<'a> { |
|
match (&*self,) { |
|
(&Code::FnLikeCode(ref __self_0),) => |
|
Code::FnLikeCode(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Code::BlockCode(ref __self_0),) => |
|
Code::BlockCode(::std::clone::Clone::clone(&(*__self_0))), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl <'a> ::std::marker::Copy for Code<'a> { } |
|
impl <'a> Code<'a> { |
|
pub fn id(&self) -> NodeId { |
|
match *self { |
|
FnLikeCode(node) => node.id(), |
|
BlockCode(block) => block.id, |
|
} |
|
} |
|
/// Attempts to construct a Code from presumed FnLike or Block node input. |
|
pub fn from_node(node: Node) -> Option<Code> { |
|
match node { |
|
map::NodeBlock(block) => { Some(BlockCode(block)) } |
|
_ => { |
|
FnLikeNode::from_node(node).map(|fn_like| |
|
FnLikeCode(fn_like)) |
|
} |
|
} |
|
} |
|
} |
|
/// These are all the components one can extract from a fn item for |
|
/// use when implementing FnLikeNode operations. |
|
struct ItemFnParts<'a> { |
|
name: Name, |
|
decl: &'a ast::FnDecl, |
|
unsafety: ast::Unsafety, |
|
constness: ast::Constness, |
|
abi: abi::Abi, |
|
vis: ast::Visibility, |
|
generics: &'a ast::Generics, |
|
body: &'a Block, |
|
id: NodeId, |
|
span: Span, |
|
} |
|
/// These are all the components one can extract from a closure expr |
|
/// for use when implementing FnLikeNode operations. |
|
struct ClosureParts<'a> { |
|
decl: &'a FnDecl, |
|
body: &'a Block, |
|
id: NodeId, |
|
span: Span, |
|
} |
|
impl <'a> ClosureParts<'a> { |
|
fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span) |
|
-> ClosureParts<'a> { |
|
ClosureParts{decl: d, body: b, id: id, span: s,} |
|
} |
|
} |
|
impl <'a> FnLikeNode<'a> { |
|
/// Attempts to construct a FnLikeNode from presumed FnLike node input. |
|
pub fn from_node(node: Node) -> Option<FnLikeNode> { |
|
let fn_like = |
|
match node { |
|
map::NodeItem(item) => item.is_fn_like(), |
|
map::NodeTraitItem(tm) => tm.is_fn_like(), |
|
map::NodeImplItem(_) => true, |
|
map::NodeExpr(e) => e.is_fn_like(), |
|
_ => false, |
|
}; |
|
if fn_like { Some(FnLikeNode{node: node,}) } else { None } |
|
} |
|
pub fn to_fn_parts(self) -> FnParts<'a> { |
|
FnParts{decl: self.decl(), |
|
body: self.body(), |
|
kind: self.kind(), |
|
span: self.span(), |
|
id: self.id(),} |
|
} |
|
pub fn body(self) -> &'a Block { |
|
self.handle(|i: ItemFnParts<'a>| &*i.body, |
|
|_, _, _: &'a ast::MethodSig, _, |
|
body: &'a ast::Block, _| body, |
|
|c: ClosureParts<'a>| c.body) |
|
} |
|
pub fn decl(self) -> &'a FnDecl { |
|
self.handle(|i: ItemFnParts<'a>| &*i.decl, |
|
|_, _, sig: &'a ast::MethodSig, _, _, _| |
|
&sig.decl, |c: ClosureParts<'a>| c.decl) |
|
} |
|
pub fn span(self) -> Span { |
|
self.handle(|i: ItemFnParts| i.span, |
|
|_, _, _: &'a ast::MethodSig, _, _, span| |
|
span, |c: ClosureParts| c.span) |
|
} |
|
pub fn id(self) -> NodeId { |
|
self.handle(|i: ItemFnParts| i.id, |
|
|id, _, _: &'a ast::MethodSig, _, _, _| id, |
|
|c: ClosureParts| c.id) |
|
} |
|
pub fn kind(self) -> FnKind<'a> { |
|
let item = |p: ItemFnParts<'a>| -> FnKind<'a> { |
|
FnKind::ItemFn(p.name, p.generics, p.unsafety, |
|
p.constness, p.abi, p.vis) }; |
|
let closure = |_: ClosureParts| { FnKind::Closure }; |
|
let method = |
|
|_, name: Name, sig: &'a ast::MethodSig, vis, _, _| { |
|
FnKind::Method(name, sig, vis) }; |
|
self.handle(item, method, closure) |
|
} |
|
fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) |
|
-> A where I: FnOnce(ItemFnParts<'a>) -> A, |
|
M: FnOnce(NodeId, Name, &'a ast::MethodSig, |
|
Option<ast::Visibility>, &'a ast::Block, Span) -> |
|
A, C: FnOnce(ClosureParts<'a>) -> A { |
|
match self.node { |
|
map::NodeItem(i) => |
|
match i.node { |
|
ast::ItemFn(ref decl, unsafety, constness, abi, |
|
ref generics, ref block) => |
|
item_fn(ItemFnParts{id: i.id, |
|
name: i.name, |
|
decl: &**decl, |
|
unsafety: unsafety, |
|
body: &**block, |
|
generics: generics, |
|
abi: abi, |
|
vis: i.vis, |
|
constness: constness, |
|
span: i.span,}), |
|
_ => { |
|
::std::rt::begin_unwind("item FnLikeNode that is not fn-like", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/blocks.rs", |
|
229u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}, |
|
map::NodeTraitItem(ti) => |
|
match ti.node { |
|
ast::MethodTraitItem(ref sig, Some(ref body)) => { |
|
method(ti.id, ti.name, sig, None, body, |
|
ti.span) |
|
} |
|
_ => { |
|
::std::rt::begin_unwind("trait method FnLikeNode that is not fn-like", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/blocks.rs", |
|
235u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}, |
|
map::NodeImplItem(ii) => { |
|
match ii.node { |
|
ast::ImplItemKind::Method(ref sig, ref body) |
|
=> { |
|
method(ii.id, ii.name, sig, Some(ii.vis), |
|
body, ii.span) |
|
} |
|
_ => { |
|
{ |
|
::std::rt::begin_unwind("impl method FnLikeNode that is not fn-like", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/front/map/blocks.rs", |
|
243u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
map::NodeExpr(e) => |
|
match e.node { |
|
ast::ExprClosure(_, ref decl, ref block) => |
|
closure(ClosureParts::new(&**decl, &**block, e.id, |
|
e.span)), |
|
_ => { |
|
::std::rt::begin_unwind("expr FnLikeNode that is not fn-like", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/blocks.rs", |
|
250u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}, |
|
_ => { |
|
::std::rt::begin_unwind("other FnLikeNode that is not fn-like", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/blocks.rs", |
|
252u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
} |
|
mod collector { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
use super::*; |
|
use super::MapEntry::*; |
|
use rustc_front::hir::*; |
|
use rustc_front::util; |
|
use rustc_front::intravisit::{self, Visitor}; |
|
use middle::def_id::{CRATE_DEF_INDEX, DefIndex}; |
|
use std::iter::repeat; |
|
use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID}; |
|
use syntax::codemap::Span; |
|
/// A Visitor that walks over an AST and collects Node's into an AST |
|
/// Map. |
|
pub struct NodeCollector<'ast> { |
|
pub krate: &'ast Crate, |
|
pub map: Vec<MapEntry<'ast>>, |
|
pub definitions: Definitions, |
|
pub parent_node: NodeId, |
|
} |
|
impl <'ast> NodeCollector<'ast> { |
|
pub fn root(krate: &'ast Crate) -> NodeCollector<'ast> { |
|
let mut collector = |
|
NodeCollector{krate: krate, |
|
map: |
|
<[_]>::into_vec(::std::boxed::Box::new([])), |
|
definitions: Definitions::new(), |
|
parent_node: CRATE_NODE_ID,}; |
|
collector.insert_entry(CRATE_NODE_ID, RootCrate); |
|
let result = |
|
collector.create_def_with_parent(None, CRATE_NODE_ID, |
|
DefPathData::CrateRoot); |
|
{ |
|
match (&(result), &(CRATE_DEF_INDEX)) { |
|
(left_val, right_val) => { |
|
if !(*left_val == *right_val) { |
|
{ |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["assertion failed: `(left == right)` (left: `", |
|
"`, right: `", |
|
"`)"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&left_val, |
|
&right_val) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/front/map/collector.rs", |
|
42u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
}; |
|
collector.create_def_with_parent(Some(CRATE_DEF_INDEX), |
|
DUMMY_NODE_ID, |
|
DefPathData::Misc); |
|
collector |
|
} |
|
pub fn extend(krate: &'ast Crate, parent: &'ast InlinedParent, |
|
parent_node: NodeId, parent_def_path: DefPath, |
|
map: Vec<MapEntry<'ast>>, |
|
definitions: Definitions) |
|
-> NodeCollector<'ast> { |
|
let mut collector = |
|
NodeCollector{krate: krate, |
|
map: map, |
|
parent_node: parent_node, |
|
definitions: definitions,}; |
|
collector.insert_entry(parent_node, |
|
RootInlinedParent(parent)); |
|
collector.create_def(parent_node, |
|
DefPathData::InlinedRoot(parent_def_path)); |
|
collector |
|
} |
|
fn parent_def(&self) -> Option<DefIndex> { |
|
let mut parent_node = Some(self.parent_node); |
|
loop { |
|
match parent_node { |
|
Some(p) => { |
|
match self.definitions.opt_def_index(p) { |
|
Some(q) => { return Some(q); } |
|
_ => (), |
|
} |
|
parent_node = |
|
self.map[p as usize].parent_node(); |
|
} |
|
_ => break , |
|
} |
|
} |
|
None |
|
} |
|
fn create_def(&mut self, node_id: NodeId, data: DefPathData) |
|
-> DefIndex { |
|
let parent_def = self.parent_def(); |
|
self.definitions.create_def_with_parent(parent_def, |
|
node_id, data) |
|
} |
|
fn create_def_with_parent(&mut self, parent: Option<DefIndex>, |
|
node_id: NodeId, data: DefPathData) |
|
-> DefIndex { |
|
self.definitions.create_def_with_parent(parent, node_id, |
|
data) |
|
} |
|
fn insert_entry(&mut self, id: NodeId, |
|
entry: MapEntry<'ast>) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 94u32, |
|
file: |
|
"src/librustc/front/map/collector.rs", |
|
module_path: |
|
"rustc::front::map::collector",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::front::map::collector") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["ast_map: ", |
|
" => "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&id, |
|
&entry) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
let len = self.map.len(); |
|
if id as usize >= len { |
|
self.map.extend(repeat(NotPresent).take(id as usize - |
|
len + 1)); |
|
} |
|
self.map[id as usize] = entry; |
|
} |
|
fn insert_def(&mut self, id: NodeId, node: Node<'ast>, |
|
data: DefPathData) -> DefIndex { |
|
self.insert(id, node); |
|
self.create_def(id, data) |
|
} |
|
fn insert(&mut self, id: NodeId, node: Node<'ast>) { |
|
let entry = MapEntry::from_node(self.parent_node, node); |
|
self.insert_entry(id, entry); |
|
} |
|
} |
|
impl <'ast> Visitor<'ast> for NodeCollector<'ast> { |
|
/// Because we want to track parent items and so forth, enable |
|
/// deep walking so that we walk nested items in the context of |
|
/// their outer items. |
|
fn visit_nested_item(&mut self, item: ItemId) { |
|
self.visit_item(self.krate.item(item.id)) |
|
} |
|
fn visit_item(&mut self, i: &'ast Item) { |
|
let def_data = |
|
match i.node { |
|
ItemDefaultImpl(..) | ItemImpl(..) => |
|
DefPathData::Impl, |
|
ItemEnum(..) | ItemStruct(..) | ItemTrait(..) => |
|
DefPathData::Type(i.name), |
|
ItemExternCrate(..) | ItemMod(..) => |
|
DefPathData::Mod(i.name), |
|
ItemStatic(..) | ItemConst(..) | ItemFn(..) => |
|
DefPathData::Value(i.name), |
|
_ => DefPathData::Misc, |
|
}; |
|
self.insert_def(i.id, NodeItem(i), def_data); |
|
let parent_node = self.parent_node; |
|
self.parent_node = i.id; |
|
match i.node { |
|
ItemImpl(..) => { } |
|
ItemEnum(ref enum_definition, _) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&enum_definition.variants) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(v) |
|
=> { |
|
let variant_def_index = |
|
self.insert_def(v.node.data.id(), |
|
NodeVariant(&**v), |
|
DefPathData::EnumVariant(v.node.name)); |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(v.node.data.fields()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(field) |
|
=> { |
|
self.create_def_with_parent(Some(variant_def_index), |
|
field.node.id, |
|
DefPathData::Field(field.node.kind)); |
|
} |
|
::std::option::Option::None |
|
=> |
|
break |
|
, |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
ItemForeignMod(..) => { } |
|
ItemStruct(ref struct_def, _) => { |
|
if !struct_def.is_struct() { |
|
self.insert_def(struct_def.id(), |
|
NodeStructCtor(struct_def), |
|
DefPathData::StructCtor); |
|
} |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(struct_def.fields()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(field) |
|
=> { |
|
self.create_def(field.node.id, |
|
DefPathData::Field(field.node.kind)); |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
ItemTrait(_, _, ref bounds, _) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(bounds.iter()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(b) |
|
=> { |
|
match *b { |
|
TraitTyParamBound(ref t, |
|
TraitBoundModifier::None) |
|
=> { |
|
self.insert(t.trait_ref.ref_id, |
|
NodeItem(i)); |
|
} |
|
_ => (), |
|
} |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
ItemUse(ref view_path) => { |
|
match view_path.node { |
|
ViewPathList(_, ref paths) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(paths) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(path) |
|
=> { |
|
self.insert(path.node.id(), |
|
NodeItem(i)); |
|
} |
|
::std::option::Option::None |
|
=> break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
_ => (), |
|
} |
|
} |
|
_ => { } |
|
} |
|
intravisit::walk_item(self, i); |
|
self.parent_node = parent_node; |
|
} |
|
fn visit_foreign_item(&mut self, |
|
foreign_item: &'ast ForeignItem) { |
|
self.insert_def(foreign_item.id, |
|
NodeForeignItem(foreign_item), |
|
DefPathData::Value(foreign_item.name)); |
|
let parent_node = self.parent_node; |
|
self.parent_node = foreign_item.id; |
|
intravisit::walk_foreign_item(self, foreign_item); |
|
self.parent_node = parent_node; |
|
} |
|
fn visit_generics(&mut self, generics: &'ast Generics) { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(generics.ty_params.iter()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(ty_param) |
|
=> { |
|
self.insert_def(ty_param.id, |
|
NodeTyParam(ty_param), |
|
DefPathData::TypeParam(ty_param.name)); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
intravisit::walk_generics(self, generics); |
|
} |
|
fn visit_trait_item(&mut self, ti: &'ast TraitItem) { |
|
let def_data = |
|
match ti.node { |
|
MethodTraitItem(..) | ConstTraitItem(..) => |
|
DefPathData::Value(ti.name), |
|
TypeTraitItem(..) => DefPathData::Type(ti.name), |
|
}; |
|
self.insert(ti.id, NodeTraitItem(ti)); |
|
self.create_def(ti.id, def_data); |
|
let parent_node = self.parent_node; |
|
self.parent_node = ti.id; |
|
match ti.node { |
|
ConstTraitItem(_, Some(ref expr)) => { |
|
self.create_def(expr.id, |
|
DefPathData::Initializer); |
|
} |
|
_ => { } |
|
} |
|
intravisit::walk_trait_item(self, ti); |
|
self.parent_node = parent_node; |
|
} |
|
fn visit_impl_item(&mut self, ii: &'ast ImplItem) { |
|
let def_data = |
|
match ii.node { |
|
ImplItemKind::Method(..) | ImplItemKind::Const(..) |
|
=> DefPathData::Value(ii.name), |
|
ImplItemKind::Type(..) => |
|
DefPathData::Type(ii.name), |
|
}; |
|
self.insert_def(ii.id, NodeImplItem(ii), def_data); |
|
let parent_node = self.parent_node; |
|
self.parent_node = ii.id; |
|
match ii.node { |
|
ImplItemKind::Const(_, ref expr) => { |
|
self.create_def(expr.id, |
|
DefPathData::Initializer); |
|
} |
|
_ => { } |
|
} |
|
intravisit::walk_impl_item(self, ii); |
|
self.parent_node = parent_node; |
|
} |
|
fn visit_pat(&mut self, pat: &'ast Pat) { |
|
let maybe_binding = |
|
match pat.node { |
|
PatIdent(_, id, _) => Some(id.node), |
|
_ => None, |
|
}; |
|
match maybe_binding { |
|
Some(id) => { |
|
self.insert_def(pat.id, NodeLocal(pat), |
|
DefPathData::Binding(id.name)); |
|
} |
|
_ => { self.insert(pat.id, NodePat(pat)); } |
|
} |
|
let parent_node = self.parent_node; |
|
self.parent_node = pat.id; |
|
intravisit::walk_pat(self, pat); |
|
self.parent_node = parent_node; |
|
} |
|
fn visit_expr(&mut self, expr: &'ast Expr) { |
|
self.insert(expr.id, NodeExpr(expr)); |
|
match expr.node { |
|
ExprClosure(..) => { |
|
self.create_def(expr.id, |
|
DefPathData::ClosureExpr); |
|
} |
|
_ => { } |
|
} |
|
let parent_node = self.parent_node; |
|
self.parent_node = expr.id; |
|
intravisit::walk_expr(self, expr); |
|
self.parent_node = parent_node; |
|
} |
|
fn visit_stmt(&mut self, stmt: &'ast Stmt) { |
|
let id = util::stmt_id(stmt); |
|
self.insert(id, NodeStmt(stmt)); |
|
let parent_node = self.parent_node; |
|
self.parent_node = id; |
|
intravisit::walk_stmt(self, stmt); |
|
self.parent_node = parent_node; |
|
} |
|
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, |
|
fd: &'ast FnDecl, b: &'ast Block, s: Span, |
|
id: NodeId) { |
|
{ |
|
match (&(self.parent_node), &(id)) { |
|
(left_val, right_val) => { |
|
if !(*left_val == *right_val) { |
|
{ |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["assertion failed: `(left == right)` (left: `", |
|
"`, right: `", |
|
"`)"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&left_val, |
|
&right_val) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/front/map/collector.rs", |
|
302u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
}; |
|
intravisit::walk_fn(self, fk, fd, b, s); |
|
} |
|
fn visit_block(&mut self, block: &'ast Block) { |
|
self.insert(block.id, NodeBlock(block)); |
|
let parent_node = self.parent_node; |
|
self.parent_node = block.id; |
|
intravisit::walk_block(self, block); |
|
self.parent_node = parent_node; |
|
} |
|
fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) { |
|
self.insert(lifetime.id, NodeLifetime(lifetime)); |
|
} |
|
fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) { |
|
self.create_def(def.lifetime.id, |
|
DefPathData::LifetimeDef(def.lifetime.name)); |
|
self.visit_lifetime(&def.lifetime); |
|
} |
|
fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) { |
|
self.create_def(macro_def.id, |
|
DefPathData::MacroDef(macro_def.name)); |
|
} |
|
} |
|
} |
|
pub mod definitions { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
use middle::cstore::LOCAL_CRATE; |
|
use middle::def_id::{DefId, DefIndex}; |
|
use rustc_data_structures::fnv::FnvHashMap; |
|
use rustc_front::hir; |
|
use syntax::ast; |
|
use syntax::parse::token::InternedString; |
|
use util::nodemap::NodeMap; |
|
pub struct Definitions { |
|
data: Vec<DefData>, |
|
key_map: FnvHashMap<DefKey, DefIndex>, |
|
node_map: NodeMap<DefIndex>, |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for Definitions { |
|
#[inline] |
|
fn clone(&self) -> Definitions { |
|
match *self { |
|
Definitions { |
|
data: ref __self_0_0, |
|
key_map: ref __self_0_1, |
|
node_map: ref __self_0_2 } => |
|
Definitions{data: |
|
::std::clone::Clone::clone(&(*__self_0_0)), |
|
key_map: |
|
::std::clone::Clone::clone(&(*__self_0_1)), |
|
node_map: |
|
::std::clone::Clone::clone(&(*__self_0_2)),}, |
|
} |
|
} |
|
} |
|
/// A unique identifier that we can use to lookup a definition |
|
/// precisely. It combines the index of the definition's parent (if |
|
/// any) with a `DisambiguatedDefPathData`. |
|
pub struct DefKey { |
|
/// Parent path. |
|
pub parent: Option<DefIndex>, |
|
/// Identifier of this node. |
|
pub disambiguated_data: DisambiguatedDefPathData, |
|
} |
|
#[automatically_derived] |
|
impl ::rustc_serialize::Decodable for DefKey { |
|
fn decode<__D: ::rustc_serialize::Decoder>(__arg_0: &mut __D) |
|
-> ::std::result::Result<DefKey, __D::Error> { |
|
__arg_0.read_struct("DefKey", 2usize, |_d| -> _ { |
|
::std::result::Result::Ok(DefKey{parent: |
|
match _d.read_struct_field("parent", |
|
0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}, |
|
disambiguated_data: |
|
match _d.read_struct_field("disambiguated_data", |
|
1usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
},}) |
|
}) |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::rustc_serialize::Encodable for DefKey { |
|
fn encode<__S: ::rustc_serialize::Encoder>(&self, |
|
__arg_0: &mut __S) |
|
-> ::std::result::Result<(), __S::Error> { |
|
match *self { |
|
DefKey { |
|
parent: ref __self_0_0, |
|
disambiguated_data: ref __self_0_1 } => |
|
__arg_0.emit_struct("DefKey", 2usize, |_e| -> _ { |
|
match _e.emit_struct_field("parent", |
|
0usize, |
|
|_e| -> |
|
_ { |
|
(*__self_0_0).encode(_e) |
|
}) { |
|
::std::result::Result::Ok(__try_var) |
|
=> __try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}; |
|
return _e.emit_struct_field("disambiguated_data", |
|
1usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0_1).encode(_e) |
|
}); }), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::hash::Hash for DefKey { |
|
fn hash<__H: ::std::hash::Hasher>(&self, __arg_0: &mut __H) |
|
-> () { |
|
match *self { |
|
DefKey { |
|
parent: ref __self_0_0, |
|
disambiguated_data: ref __self_0_1 } => { |
|
::std::hash::Hash::hash(&(*__self_0_0), __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0_1), __arg_0); |
|
} |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::Eq for DefKey { |
|
#[inline] |
|
#[doc(hidden)] |
|
fn assert_receiver_is_total_eq(&self) -> () { |
|
match *self { |
|
DefKey { |
|
parent: ref __self_0_0, |
|
disambiguated_data: ref __self_0_1 } => { |
|
(*__self_0_0).assert_receiver_is_total_eq(); |
|
(*__self_0_1).assert_receiver_is_total_eq(); |
|
} |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for DefKey { |
|
#[inline] |
|
fn eq(&self, __arg_0: &DefKey) -> bool { |
|
match *__arg_0 { |
|
DefKey { |
|
parent: ref __self_1_0, |
|
disambiguated_data: ref __self_1_1 } => |
|
match *self { |
|
DefKey { |
|
parent: ref __self_0_0, |
|
disambiguated_data: ref __self_0_1 } => |
|
true && (*__self_0_0) == (*__self_1_0) && |
|
(*__self_0_1) == (*__self_1_1), |
|
}, |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &DefKey) -> bool { |
|
match *__arg_0 { |
|
DefKey { |
|
parent: ref __self_1_0, |
|
disambiguated_data: ref __self_1_1 } => |
|
match *self { |
|
DefKey { |
|
parent: ref __self_0_0, |
|
disambiguated_data: ref __self_0_1 } => |
|
false || (*__self_0_0) != (*__self_1_0) || |
|
(*__self_0_1) != (*__self_1_1), |
|
}, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for DefKey { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match *self { |
|
DefKey { |
|
parent: ref __self_0_0, |
|
disambiguated_data: ref __self_0_1 } => |
|
__arg_0.debug_struct("DefKey").field("parent", |
|
&&(*__self_0_0)).field("disambiguated_data", |
|
&&(*__self_0_1)).finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for DefKey { |
|
#[inline] |
|
fn clone(&self) -> DefKey { |
|
match *self { |
|
DefKey { |
|
parent: ref __self_0_0, |
|
disambiguated_data: ref __self_0_1 } => |
|
DefKey{parent: |
|
::std::clone::Clone::clone(&(*__self_0_0)), |
|
disambiguated_data: |
|
::std::clone::Clone::clone(&(*__self_0_1)),}, |
|
} |
|
} |
|
} |
|
/// Pair of `DefPathData` and an integer disambiguator. The integer is |
|
/// normally 0, but in the event that there are multiple defs with the |
|
/// same `parent` and `data`, we use this field to disambiguate |
|
/// between them. This introduces some artificial ordering dependency |
|
/// but means that if you have (e.g.) two impls for the same type in |
|
/// the same module, they do get distinct def-ids. |
|
pub struct DisambiguatedDefPathData { |
|
pub data: DefPathData, |
|
pub disambiguator: u32, |
|
} |
|
#[automatically_derived] |
|
impl ::rustc_serialize::Decodable for DisambiguatedDefPathData { |
|
fn decode<__D: ::rustc_serialize::Decoder>(__arg_0: &mut __D) |
|
-> |
|
::std::result::Result<DisambiguatedDefPathData, |
|
__D::Error> { |
|
__arg_0.read_struct("DisambiguatedDefPathData", 2usize, |
|
|_d| -> _ { |
|
::std::result::Result::Ok(DisambiguatedDefPathData{data: |
|
match _d.read_struct_field("data", |
|
0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}, |
|
disambiguator: |
|
match _d.read_struct_field("disambiguator", |
|
1usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
},}) |
|
}) |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::rustc_serialize::Encodable for DisambiguatedDefPathData { |
|
fn encode<__S: ::rustc_serialize::Encoder>(&self, |
|
__arg_0: &mut __S) |
|
-> ::std::result::Result<(), __S::Error> { |
|
match *self { |
|
DisambiguatedDefPathData { |
|
data: ref __self_0_0, disambiguator: ref __self_0_1 } |
|
=> |
|
__arg_0.emit_struct("DisambiguatedDefPathData", |
|
2usize, |_e| -> _ { |
|
match _e.emit_struct_field("data", |
|
0usize, |
|
|_e| -> |
|
_ { |
|
(*__self_0_0).encode(_e) |
|
}) { |
|
::std::result::Result::Ok(__try_var) |
|
=> __try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}; |
|
return _e.emit_struct_field("disambiguator", |
|
1usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0_1).encode(_e) |
|
}); }), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::hash::Hash for DisambiguatedDefPathData { |
|
fn hash<__H: ::std::hash::Hasher>(&self, __arg_0: &mut __H) |
|
-> () { |
|
match *self { |
|
DisambiguatedDefPathData { |
|
data: ref __self_0_0, disambiguator: ref __self_0_1 } |
|
=> { |
|
::std::hash::Hash::hash(&(*__self_0_0), __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0_1), __arg_0); |
|
} |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::Eq for DisambiguatedDefPathData { |
|
#[inline] |
|
#[doc(hidden)] |
|
fn assert_receiver_is_total_eq(&self) -> () { |
|
match *self { |
|
DisambiguatedDefPathData { |
|
data: ref __self_0_0, disambiguator: ref __self_0_1 } |
|
=> { |
|
(*__self_0_0).assert_receiver_is_total_eq(); |
|
(*__self_0_1).assert_receiver_is_total_eq(); |
|
} |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for DisambiguatedDefPathData { |
|
#[inline] |
|
fn eq(&self, __arg_0: &DisambiguatedDefPathData) -> bool { |
|
match *__arg_0 { |
|
DisambiguatedDefPathData { |
|
data: ref __self_1_0, disambiguator: ref __self_1_1 } |
|
=> |
|
match *self { |
|
DisambiguatedDefPathData { |
|
data: ref __self_0_0, |
|
disambiguator: ref __self_0_1 } => |
|
true && (*__self_0_0) == (*__self_1_0) && |
|
(*__self_0_1) == (*__self_1_1), |
|
}, |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &DisambiguatedDefPathData) -> bool { |
|
match *__arg_0 { |
|
DisambiguatedDefPathData { |
|
data: ref __self_1_0, disambiguator: ref __self_1_1 } |
|
=> |
|
match *self { |
|
DisambiguatedDefPathData { |
|
data: ref __self_0_0, |
|
disambiguator: ref __self_0_1 } => |
|
false || (*__self_0_0) != (*__self_1_0) || |
|
(*__self_0_1) != (*__self_1_1), |
|
}, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for DisambiguatedDefPathData { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match *self { |
|
DisambiguatedDefPathData { |
|
data: ref __self_0_0, disambiguator: ref __self_0_1 } |
|
=> |
|
__arg_0.debug_struct("DisambiguatedDefPathData").field("data", |
|
&&(*__self_0_0)).field("disambiguator", |
|
&&(*__self_0_1)).finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for DisambiguatedDefPathData { |
|
#[inline] |
|
fn clone(&self) -> DisambiguatedDefPathData { |
|
match *self { |
|
DisambiguatedDefPathData { |
|
data: ref __self_0_0, disambiguator: ref __self_0_1 } |
|
=> |
|
DisambiguatedDefPathData{data: |
|
::std::clone::Clone::clone(&(*__self_0_0)), |
|
disambiguator: |
|
::std::clone::Clone::clone(&(*__self_0_1)),}, |
|
} |
|
} |
|
} |
|
/// For each definition, we track the following data. A definition |
|
/// here is defined somewhat circularly as "something with a def-id", |
|
/// but it generally corresponds to things like structs, enums, etc. |
|
/// There are also some rather random cases (like const initializer |
|
/// expressions) that are mostly just leftovers. |
|
pub struct DefData { |
|
pub key: DefKey, |
|
/// Local ID within the HIR. |
|
pub node_id: ast::NodeId, |
|
} |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for DefData { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match *self { |
|
DefData { key: ref __self_0_0, node_id: ref __self_0_1 |
|
} => |
|
__arg_0.debug_struct("DefData").field("key", |
|
&&(*__self_0_0)).field("node_id", |
|
&&(*__self_0_1)).finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for DefData { |
|
#[inline] |
|
fn clone(&self) -> DefData { |
|
match *self { |
|
DefData { key: ref __self_0_0, node_id: ref __self_0_1 |
|
} => |
|
DefData{key: |
|
::std::clone::Clone::clone(&(*__self_0_0)), |
|
node_id: |
|
::std::clone::Clone::clone(&(*__self_0_1)),}, |
|
} |
|
} |
|
} |
|
pub type DefPath = Vec<DisambiguatedDefPathData>; |
|
pub enum DefPathData { |
|
CrateRoot, |
|
InlinedRoot(DefPath), |
|
Misc, |
|
Impl, |
|
Type(ast::Name), |
|
Mod(ast::Name), |
|
Value(ast::Name), |
|
MacroDef(ast::Name), |
|
ClosureExpr, |
|
TypeParam(ast::Name), |
|
LifetimeDef(ast::Name), |
|
EnumVariant(ast::Name), |
|
PositionalField, |
|
Field(hir::StructFieldKind), |
|
StructCtor, |
|
Initializer, |
|
Binding(ast::Name), |
|
DetachedCrate(ast::Name), |
|
} |
|
#[automatically_derived] |
|
impl ::rustc_serialize::Decodable for DefPathData { |
|
fn decode<__D: ::rustc_serialize::Decoder>(__arg_0: &mut __D) |
|
-> ::std::result::Result<DefPathData, __D::Error> { |
|
__arg_0.read_enum("DefPathData", |_d| -> _ { |
|
_d.read_enum_variant(&["CrateRoot", |
|
"InlinedRoot", |
|
"Misc", "Impl", |
|
"Type", "Mod", |
|
"Value", |
|
"MacroDef", |
|
"ClosureExpr", |
|
"TypeParam", |
|
"LifetimeDef", |
|
"EnumVariant", |
|
"PositionalField", |
|
"Field", |
|
"StructCtor", |
|
"Initializer", |
|
"Binding", |
|
"DetachedCrate"], |
|
|_d, i| -> _ { |
|
::std::result::Result::Ok(match i |
|
{ |
|
0usize |
|
=> |
|
DefPathData::CrateRoot, |
|
1usize |
|
=> |
|
DefPathData::InlinedRoot(match _d.read_enum_variant_arg(0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}), |
|
2usize |
|
=> |
|
DefPathData::Misc, |
|
3usize |
|
=> |
|
DefPathData::Impl, |
|
4usize |
|
=> |
|
DefPathData::Type(match _d.read_enum_variant_arg(0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}), |
|
5usize |
|
=> |
|
DefPathData::Mod(match _d.read_enum_variant_arg(0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}), |
|
6usize |
|
=> |
|
DefPathData::Value(match _d.read_enum_variant_arg(0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}), |
|
7usize |
|
=> |
|
DefPathData::MacroDef(match _d.read_enum_variant_arg(0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}), |
|
8usize |
|
=> |
|
DefPathData::ClosureExpr, |
|
9usize |
|
=> |
|
DefPathData::TypeParam(match _d.read_enum_variant_arg(0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}), |
|
10usize |
|
=> |
|
DefPathData::LifetimeDef(match _d.read_enum_variant_arg(0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}), |
|
11usize |
|
=> |
|
DefPathData::EnumVariant(match _d.read_enum_variant_arg(0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}), |
|
12usize |
|
=> |
|
DefPathData::PositionalField, |
|
13usize |
|
=> |
|
DefPathData::Field(match _d.read_enum_variant_arg(0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}), |
|
14usize |
|
=> |
|
DefPathData::StructCtor, |
|
15usize |
|
=> |
|
DefPathData::Initializer, |
|
16usize |
|
=> |
|
DefPathData::Binding(match _d.read_enum_variant_arg(0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}), |
|
17usize |
|
=> |
|
DefPathData::DetachedCrate(match _d.read_enum_variant_arg(0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
}), |
|
_ |
|
=> |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
&("src/librustc/front/map/definitions.rs", |
|
65u32)), |
|
}) |
|
}) }) |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::rustc_serialize::Encodable for DefPathData { |
|
fn encode<__S: ::rustc_serialize::Encoder>(&self, |
|
__arg_0: &mut __S) |
|
-> ::std::result::Result<(), __S::Error> { |
|
match (&*self,) { |
|
(&DefPathData::CrateRoot,) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("CrateRoot", |
|
0usize, 0usize, |
|
|_e| -> _ { |
|
return ::std::result::Result::Ok(()); |
|
}) }) |
|
} |
|
(&DefPathData::InlinedRoot(ref __self_0),) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("InlinedRoot", |
|
1usize, 1usize, |
|
|_e| -> _ { |
|
return _e.emit_enum_variant_arg(0usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0).encode(_e) |
|
}); |
|
}) }) |
|
} |
|
(&DefPathData::Misc,) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("Misc", 2usize, |
|
0usize, |
|
|_e| -> _ { |
|
return ::std::result::Result::Ok(()); |
|
}) }) |
|
} |
|
(&DefPathData::Impl,) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("Impl", 3usize, |
|
0usize, |
|
|_e| -> _ { |
|
return ::std::result::Result::Ok(()); |
|
}) }) |
|
} |
|
(&DefPathData::Type(ref __self_0),) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("Type", 4usize, |
|
1usize, |
|
|_e| -> _ { |
|
return _e.emit_enum_variant_arg(0usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0).encode(_e) |
|
}); |
|
}) }) |
|
} |
|
(&DefPathData::Mod(ref __self_0),) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("Mod", 5usize, |
|
1usize, |
|
|_e| -> _ { |
|
return _e.emit_enum_variant_arg(0usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0).encode(_e) |
|
}); |
|
}) }) |
|
} |
|
(&DefPathData::Value(ref __self_0),) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("Value", 6usize, |
|
1usize, |
|
|_e| -> _ { |
|
return _e.emit_enum_variant_arg(0usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0).encode(_e) |
|
}); |
|
}) }) |
|
} |
|
(&DefPathData::MacroDef(ref __self_0),) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("MacroDef", |
|
7usize, 1usize, |
|
|_e| -> _ { |
|
return _e.emit_enum_variant_arg(0usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0).encode(_e) |
|
}); |
|
}) }) |
|
} |
|
(&DefPathData::ClosureExpr,) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("ClosureExpr", |
|
8usize, 0usize, |
|
|_e| -> _ { |
|
return ::std::result::Result::Ok(()); |
|
}) }) |
|
} |
|
(&DefPathData::TypeParam(ref __self_0),) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("TypeParam", |
|
9usize, 1usize, |
|
|_e| -> _ { |
|
return _e.emit_enum_variant_arg(0usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0).encode(_e) |
|
}); |
|
}) }) |
|
} |
|
(&DefPathData::LifetimeDef(ref __self_0),) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("LifetimeDef", |
|
10usize, 1usize, |
|
|_e| -> _ { |
|
return _e.emit_enum_variant_arg(0usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0).encode(_e) |
|
}); |
|
}) }) |
|
} |
|
(&DefPathData::EnumVariant(ref __self_0),) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("EnumVariant", |
|
11usize, 1usize, |
|
|_e| -> _ { |
|
return _e.emit_enum_variant_arg(0usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0).encode(_e) |
|
}); |
|
}) }) |
|
} |
|
(&DefPathData::PositionalField,) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("PositionalField", |
|
12usize, 0usize, |
|
|_e| -> _ { |
|
return ::std::result::Result::Ok(()); |
|
}) }) |
|
} |
|
(&DefPathData::Field(ref __self_0),) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("Field", |
|
13usize, 1usize, |
|
|_e| -> _ { |
|
return _e.emit_enum_variant_arg(0usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0).encode(_e) |
|
}); |
|
}) }) |
|
} |
|
(&DefPathData::StructCtor,) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("StructCtor", |
|
14usize, 0usize, |
|
|_e| -> _ { |
|
return ::std::result::Result::Ok(()); |
|
}) }) |
|
} |
|
(&DefPathData::Initializer,) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("Initializer", |
|
15usize, 0usize, |
|
|_e| -> _ { |
|
return ::std::result::Result::Ok(()); |
|
}) }) |
|
} |
|
(&DefPathData::Binding(ref __self_0),) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("Binding", |
|
16usize, 1usize, |
|
|_e| -> _ { |
|
return _e.emit_enum_variant_arg(0usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0).encode(_e) |
|
}); |
|
}) }) |
|
} |
|
(&DefPathData::DetachedCrate(ref __self_0),) => { |
|
let _e = __arg_0; |
|
_e.emit_enum("DefPathData", |_e| -> _ { |
|
_e.emit_enum_variant("DetachedCrate", |
|
17usize, 1usize, |
|
|_e| -> _ { |
|
return _e.emit_enum_variant_arg(0usize, |
|
|_e| |
|
-> |
|
_ |
|
{ |
|
(*__self_0).encode(_e) |
|
}); |
|
}) }) |
|
} |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::hash::Hash for DefPathData { |
|
fn hash<__H: ::std::hash::Hasher>(&self, __arg_0: &mut __H) |
|
-> () { |
|
match (&*self,) { |
|
(&DefPathData::CrateRoot,) => { |
|
::std::hash::Hash::hash(&0usize, __arg_0); |
|
} |
|
(&DefPathData::InlinedRoot(ref __self_0),) => { |
|
::std::hash::Hash::hash(&1usize, __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0), __arg_0); |
|
} |
|
(&DefPathData::Misc,) => { |
|
::std::hash::Hash::hash(&2usize, __arg_0); |
|
} |
|
(&DefPathData::Impl,) => { |
|
::std::hash::Hash::hash(&3usize, __arg_0); |
|
} |
|
(&DefPathData::Type(ref __self_0),) => { |
|
::std::hash::Hash::hash(&4usize, __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0), __arg_0); |
|
} |
|
(&DefPathData::Mod(ref __self_0),) => { |
|
::std::hash::Hash::hash(&5usize, __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0), __arg_0); |
|
} |
|
(&DefPathData::Value(ref __self_0),) => { |
|
::std::hash::Hash::hash(&6usize, __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0), __arg_0); |
|
} |
|
(&DefPathData::MacroDef(ref __self_0),) => { |
|
::std::hash::Hash::hash(&7usize, __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0), __arg_0); |
|
} |
|
(&DefPathData::ClosureExpr,) => { |
|
::std::hash::Hash::hash(&8usize, __arg_0); |
|
} |
|
(&DefPathData::TypeParam(ref __self_0),) => { |
|
::std::hash::Hash::hash(&9usize, __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0), __arg_0); |
|
} |
|
(&DefPathData::LifetimeDef(ref __self_0),) => { |
|
::std::hash::Hash::hash(&10usize, __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0), __arg_0); |
|
} |
|
(&DefPathData::EnumVariant(ref __self_0),) => { |
|
::std::hash::Hash::hash(&11usize, __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0), __arg_0); |
|
} |
|
(&DefPathData::PositionalField,) => { |
|
::std::hash::Hash::hash(&12usize, __arg_0); |
|
} |
|
(&DefPathData::Field(ref __self_0),) => { |
|
::std::hash::Hash::hash(&13usize, __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0), __arg_0); |
|
} |
|
(&DefPathData::StructCtor,) => { |
|
::std::hash::Hash::hash(&14usize, __arg_0); |
|
} |
|
(&DefPathData::Initializer,) => { |
|
::std::hash::Hash::hash(&15usize, __arg_0); |
|
} |
|
(&DefPathData::Binding(ref __self_0),) => { |
|
::std::hash::Hash::hash(&16usize, __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0), __arg_0); |
|
} |
|
(&DefPathData::DetachedCrate(ref __self_0),) => { |
|
::std::hash::Hash::hash(&17usize, __arg_0); |
|
::std::hash::Hash::hash(&(*__self_0), __arg_0); |
|
} |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::Eq for DefPathData { |
|
#[inline] |
|
#[doc(hidden)] |
|
fn assert_receiver_is_total_eq(&self) -> () { |
|
match (&*self,) { |
|
(&DefPathData::CrateRoot,) => { } |
|
(&DefPathData::InlinedRoot(ref __self_0),) => { |
|
(*__self_0).assert_receiver_is_total_eq(); |
|
} |
|
(&DefPathData::Misc,) => { } |
|
(&DefPathData::Impl,) => { } |
|
(&DefPathData::Type(ref __self_0),) => { |
|
(*__self_0).assert_receiver_is_total_eq(); |
|
} |
|
(&DefPathData::Mod(ref __self_0),) => { |
|
(*__self_0).assert_receiver_is_total_eq(); |
|
} |
|
(&DefPathData::Value(ref __self_0),) => { |
|
(*__self_0).assert_receiver_is_total_eq(); |
|
} |
|
(&DefPathData::MacroDef(ref __self_0),) => { |
|
(*__self_0).assert_receiver_is_total_eq(); |
|
} |
|
(&DefPathData::ClosureExpr,) => { } |
|
(&DefPathData::TypeParam(ref __self_0),) => { |
|
(*__self_0).assert_receiver_is_total_eq(); |
|
} |
|
(&DefPathData::LifetimeDef(ref __self_0),) => { |
|
(*__self_0).assert_receiver_is_total_eq(); |
|
} |
|
(&DefPathData::EnumVariant(ref __self_0),) => { |
|
(*__self_0).assert_receiver_is_total_eq(); |
|
} |
|
(&DefPathData::PositionalField,) => { } |
|
(&DefPathData::Field(ref __self_0),) => { |
|
(*__self_0).assert_receiver_is_total_eq(); |
|
} |
|
(&DefPathData::StructCtor,) => { } |
|
(&DefPathData::Initializer,) => { } |
|
(&DefPathData::Binding(ref __self_0),) => { |
|
(*__self_0).assert_receiver_is_total_eq(); |
|
} |
|
(&DefPathData::DetachedCrate(ref __self_0),) => { |
|
(*__self_0).assert_receiver_is_total_eq(); |
|
} |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for DefPathData { |
|
#[inline] |
|
fn eq(&self, __arg_0: &DefPathData) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&DefPathData::CrateRoot, |
|
&DefPathData::CrateRoot) => true, |
|
(&DefPathData::InlinedRoot(ref __self_0), |
|
&DefPathData::InlinedRoot(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&DefPathData::Misc, &DefPathData::Misc) => |
|
true, |
|
(&DefPathData::Impl, &DefPathData::Impl) => |
|
true, |
|
(&DefPathData::Type(ref __self_0), |
|
&DefPathData::Type(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&DefPathData::Mod(ref __self_0), |
|
&DefPathData::Mod(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&DefPathData::Value(ref __self_0), |
|
&DefPathData::Value(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&DefPathData::MacroDef(ref __self_0), |
|
&DefPathData::MacroDef(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&DefPathData::ClosureExpr, |
|
&DefPathData::ClosureExpr) => true, |
|
(&DefPathData::TypeParam(ref __self_0), |
|
&DefPathData::TypeParam(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&DefPathData::LifetimeDef(ref __self_0), |
|
&DefPathData::LifetimeDef(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&DefPathData::EnumVariant(ref __self_0), |
|
&DefPathData::EnumVariant(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&DefPathData::PositionalField, |
|
&DefPathData::PositionalField) => true, |
|
(&DefPathData::Field(ref __self_0), |
|
&DefPathData::Field(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&DefPathData::StructCtor, |
|
&DefPathData::StructCtor) => true, |
|
(&DefPathData::Initializer, |
|
&DefPathData::Initializer) => true, |
|
(&DefPathData::Binding(ref __self_0), |
|
&DefPathData::Binding(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&DefPathData::DetachedCrate(ref __self_0), |
|
&DefPathData::DetachedCrate(ref __arg_1_0)) |
|
=> true && (*__self_0) == (*__arg_1_0), |
|
_ => unsafe { |
|
::std::intrinsics::unreachable() |
|
} |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &DefPathData) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&DefPathData::CrateRoot, |
|
&DefPathData::CrateRoot) => false, |
|
(&DefPathData::InlinedRoot(ref __self_0), |
|
&DefPathData::InlinedRoot(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&DefPathData::Misc, &DefPathData::Misc) => |
|
false, |
|
(&DefPathData::Impl, &DefPathData::Impl) => |
|
false, |
|
(&DefPathData::Type(ref __self_0), |
|
&DefPathData::Type(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&DefPathData::Mod(ref __self_0), |
|
&DefPathData::Mod(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&DefPathData::Value(ref __self_0), |
|
&DefPathData::Value(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&DefPathData::MacroDef(ref __self_0), |
|
&DefPathData::MacroDef(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&DefPathData::ClosureExpr, |
|
&DefPathData::ClosureExpr) => false, |
|
(&DefPathData::TypeParam(ref __self_0), |
|
&DefPathData::TypeParam(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&DefPathData::LifetimeDef(ref __self_0), |
|
&DefPathData::LifetimeDef(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&DefPathData::EnumVariant(ref __self_0), |
|
&DefPathData::EnumVariant(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&DefPathData::PositionalField, |
|
&DefPathData::PositionalField) => false, |
|
(&DefPathData::Field(ref __self_0), |
|
&DefPathData::Field(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&DefPathData::StructCtor, |
|
&DefPathData::StructCtor) => false, |
|
(&DefPathData::Initializer, |
|
&DefPathData::Initializer) => false, |
|
(&DefPathData::Binding(ref __self_0), |
|
&DefPathData::Binding(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&DefPathData::DetachedCrate(ref __self_0), |
|
&DefPathData::DetachedCrate(ref __arg_1_0)) |
|
=> false || (*__self_0) != (*__arg_1_0), |
|
_ => unsafe { |
|
::std::intrinsics::unreachable() |
|
} |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for DefPathData { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&DefPathData::CrateRoot,) => |
|
__arg_0.debug_tuple("CrateRoot").finish(), |
|
(&DefPathData::InlinedRoot(ref __self_0),) => |
|
__arg_0.debug_tuple("InlinedRoot").field(&&(*__self_0)).finish(), |
|
(&DefPathData::Misc,) => |
|
__arg_0.debug_tuple("Misc").finish(), |
|
(&DefPathData::Impl,) => |
|
__arg_0.debug_tuple("Impl").finish(), |
|
(&DefPathData::Type(ref __self_0),) => |
|
__arg_0.debug_tuple("Type").field(&&(*__self_0)).finish(), |
|
(&DefPathData::Mod(ref __self_0),) => |
|
__arg_0.debug_tuple("Mod").field(&&(*__self_0)).finish(), |
|
(&DefPathData::Value(ref __self_0),) => |
|
__arg_0.debug_tuple("Value").field(&&(*__self_0)).finish(), |
|
(&DefPathData::MacroDef(ref __self_0),) => |
|
__arg_0.debug_tuple("MacroDef").field(&&(*__self_0)).finish(), |
|
(&DefPathData::ClosureExpr,) => |
|
__arg_0.debug_tuple("ClosureExpr").finish(), |
|
(&DefPathData::TypeParam(ref __self_0),) => |
|
__arg_0.debug_tuple("TypeParam").field(&&(*__self_0)).finish(), |
|
(&DefPathData::LifetimeDef(ref __self_0),) => |
|
__arg_0.debug_tuple("LifetimeDef").field(&&(*__self_0)).finish(), |
|
(&DefPathData::EnumVariant(ref __self_0),) => |
|
__arg_0.debug_tuple("EnumVariant").field(&&(*__self_0)).finish(), |
|
(&DefPathData::PositionalField,) => |
|
__arg_0.debug_tuple("PositionalField").finish(), |
|
(&DefPathData::Field(ref __self_0),) => |
|
__arg_0.debug_tuple("Field").field(&&(*__self_0)).finish(), |
|
(&DefPathData::StructCtor,) => |
|
__arg_0.debug_tuple("StructCtor").finish(), |
|
(&DefPathData::Initializer,) => |
|
__arg_0.debug_tuple("Initializer").finish(), |
|
(&DefPathData::Binding(ref __self_0),) => |
|
__arg_0.debug_tuple("Binding").field(&&(*__self_0)).finish(), |
|
(&DefPathData::DetachedCrate(ref __self_0),) => |
|
__arg_0.debug_tuple("DetachedCrate").field(&&(*__self_0)).finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for DefPathData { |
|
#[inline] |
|
fn clone(&self) -> DefPathData { |
|
match (&*self,) { |
|
(&DefPathData::CrateRoot,) => DefPathData::CrateRoot, |
|
(&DefPathData::InlinedRoot(ref __self_0),) => |
|
DefPathData::InlinedRoot(::std::clone::Clone::clone(&(*__self_0))), |
|
(&DefPathData::Misc,) => DefPathData::Misc, |
|
(&DefPathData::Impl,) => DefPathData::Impl, |
|
(&DefPathData::Type(ref __self_0),) => |
|
DefPathData::Type(::std::clone::Clone::clone(&(*__self_0))), |
|
(&DefPathData::Mod(ref __self_0),) => |
|
DefPathData::Mod(::std::clone::Clone::clone(&(*__self_0))), |
|
(&DefPathData::Value(ref __self_0),) => |
|
DefPathData::Value(::std::clone::Clone::clone(&(*__self_0))), |
|
(&DefPathData::MacroDef(ref __self_0),) => |
|
DefPathData::MacroDef(::std::clone::Clone::clone(&(*__self_0))), |
|
(&DefPathData::ClosureExpr,) => |
|
DefPathData::ClosureExpr, |
|
(&DefPathData::TypeParam(ref __self_0),) => |
|
DefPathData::TypeParam(::std::clone::Clone::clone(&(*__self_0))), |
|
(&DefPathData::LifetimeDef(ref __self_0),) => |
|
DefPathData::LifetimeDef(::std::clone::Clone::clone(&(*__self_0))), |
|
(&DefPathData::EnumVariant(ref __self_0),) => |
|
DefPathData::EnumVariant(::std::clone::Clone::clone(&(*__self_0))), |
|
(&DefPathData::PositionalField,) => |
|
DefPathData::PositionalField, |
|
(&DefPathData::Field(ref __self_0),) => |
|
DefPathData::Field(::std::clone::Clone::clone(&(*__self_0))), |
|
(&DefPathData::StructCtor,) => |
|
DefPathData::StructCtor, |
|
(&DefPathData::Initializer,) => |
|
DefPathData::Initializer, |
|
(&DefPathData::Binding(ref __self_0),) => |
|
DefPathData::Binding(::std::clone::Clone::clone(&(*__self_0))), |
|
(&DefPathData::DetachedCrate(ref __self_0),) => |
|
DefPathData::DetachedCrate(::std::clone::Clone::clone(&(*__self_0))), |
|
} |
|
} |
|
} |
|
impl Definitions { |
|
pub fn new() -> Definitions { |
|
Definitions{data: |
|
<[_]>::into_vec(::std::boxed::Box::new([])), |
|
key_map: FnvHashMap(), |
|
node_map: NodeMap(),} |
|
} |
|
pub fn len(&self) -> usize { self.data.len() } |
|
pub fn def_key(&self, index: DefIndex) -> DefKey { |
|
self.data[index.as_usize()].key.clone() |
|
} |
|
/// Returns the path from the crate root to `index`. The root |
|
/// nodes are not included in the path (i.e., this will be an |
|
/// empty vector for the crate root). For an inlined item, this |
|
/// will be the path of the item in the external crate (but the |
|
/// path will begin with the path to the external crate). |
|
pub fn def_path(&self, index: DefIndex) -> DefPath { |
|
make_def_path(index, |p| self.def_key(p)) |
|
} |
|
pub fn opt_def_index(&self, node: ast::NodeId) |
|
-> Option<DefIndex> { |
|
self.node_map.get(&node).cloned() |
|
} |
|
pub fn opt_local_def_id(&self, node: ast::NodeId) |
|
-> Option<DefId> { |
|
self.opt_def_index(node).map(DefId::local) |
|
} |
|
pub fn as_local_node_id(&self, def_id: DefId) |
|
-> Option<ast::NodeId> { |
|
if def_id.krate == LOCAL_CRATE { |
|
if !(def_id.index.as_usize() < self.data.len()) { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: def_id.index.as_usize() < self.data.len()", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/definitions.rs", |
|
134u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
Some(self.data[def_id.index.as_usize()].node_id) |
|
} else { None } |
|
} |
|
pub fn create_def_with_parent(&mut self, |
|
parent: Option<DefIndex>, |
|
node_id: ast::NodeId, |
|
data: DefPathData) -> DefIndex { |
|
if !!self.node_map.contains_key(&node_id) { |
|
{ |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["adding a def\'n for node-id ", |
|
" and data ", |
|
" but a previous def\'n exists: "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&node_id, |
|
&data, |
|
&self.data[self.node_map[&node_id].as_usize()]) |
|
{ |
|
(__arg0, |
|
__arg1, |
|
__arg2) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg2, |
|
::std::fmt::Debug::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/definitions.rs", |
|
146u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
let mut key = |
|
DefKey{parent: parent, |
|
disambiguated_data: |
|
DisambiguatedDefPathData{data: data, |
|
disambiguator: |
|
0,},}; |
|
while self.key_map.contains_key(&key) { |
|
key.disambiguated_data.disambiguator += 1; |
|
} |
|
let index = DefIndex::new(self.data.len()); |
|
self.data.push(DefData{key: key.clone(), |
|
node_id: node_id,}); |
|
self.node_map.insert(node_id, index); |
|
self.key_map.insert(key, index); |
|
index |
|
} |
|
} |
|
impl DefPathData { |
|
pub fn as_interned_str(&self) -> InternedString { |
|
use self::DefPathData::*; |
|
match *self { |
|
Type(name) | Mod(name) | Value(name) | MacroDef(name) |
|
| TypeParam(name) | LifetimeDef(name) | |
|
EnumVariant(name) | DetachedCrate(name) | |
|
Binding(name) => { |
|
name.as_str() |
|
} |
|
Field(hir::StructFieldKind::NamedField(name, _)) => { |
|
name.as_str() |
|
} |
|
PositionalField | |
|
Field(hir::StructFieldKind::UnnamedField(_)) => { |
|
InternedString::new("<field>") |
|
} |
|
CrateRoot => { InternedString::new("<root>") } |
|
InlinedRoot(_) => { |
|
InternedString::new("<inlined-root>") |
|
} |
|
Misc => { InternedString::new("?") } |
|
Impl => { InternedString::new("<impl>") } |
|
ClosureExpr => { InternedString::new("<closure>") } |
|
StructCtor => { InternedString::new("<constructor>") } |
|
Initializer => { |
|
InternedString::new("<initializer>") |
|
} |
|
} |
|
} |
|
pub fn to_string(&self) -> String { |
|
self.as_interned_str().to_string() |
|
} |
|
} |
|
pub fn make_def_path<FN>(start_index: DefIndex, mut get_key: FN) |
|
-> DefPath where FN: FnMut(DefIndex) -> DefKey { |
|
let mut result = <[_]>::into_vec(::std::boxed::Box::new([])); |
|
let mut index = Some(start_index); |
|
loop { |
|
match index { |
|
Some(p) => { |
|
let key = get_key(p); |
|
match key.disambiguated_data.data { |
|
DefPathData::CrateRoot => { |
|
if !key.parent.is_none() { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: key.parent.is_none()", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/front/map/definitions.rs", |
|
247u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
break ; |
|
} |
|
DefPathData::InlinedRoot(ref p) => { |
|
if !key.parent.is_none() { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: key.parent.is_none()", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/front/map/definitions.rs", |
|
251u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
result.extend(p.iter().cloned().rev()); |
|
break ; |
|
} |
|
_ => { |
|
result.push(key.disambiguated_data); |
|
index = key.parent; |
|
} |
|
} |
|
} |
|
_ => break , |
|
} |
|
} |
|
result.reverse(); |
|
result |
|
} |
|
} |
|
pub enum PathElem { PathMod(Name), PathName(Name), } |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for PathElem { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&PathElem::PathMod(ref __self_0),) => |
|
__arg_0.debug_tuple("PathMod").field(&&(*__self_0)).finish(), |
|
(&PathElem::PathName(ref __self_0),) => |
|
__arg_0.debug_tuple("PathName").field(&&(*__self_0)).finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for PathElem { |
|
#[inline] |
|
fn eq(&self, __arg_0: &PathElem) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&PathElem::PathMod(ref __self_0), |
|
&PathElem::PathMod(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&PathElem::PathName(ref __self_0), |
|
&PathElem::PathName(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &PathElem) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&PathElem::PathMod(ref __self_0), |
|
&PathElem::PathMod(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&PathElem::PathName(ref __self_0), |
|
&PathElem::PathName(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for PathElem { } |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for PathElem { |
|
#[inline] |
|
fn clone(&self) -> PathElem { |
|
match (&*self,) { |
|
(&PathElem::PathMod(ref __self_0),) => |
|
PathElem::PathMod(::std::clone::Clone::clone(&(*__self_0))), |
|
(&PathElem::PathName(ref __self_0),) => |
|
PathElem::PathName(::std::clone::Clone::clone(&(*__self_0))), |
|
} |
|
} |
|
} |
|
impl PathElem { |
|
pub fn name(&self) -> Name { |
|
match *self { PathMod(name) | PathName(name) => name, } |
|
} |
|
} |
|
impl fmt::Display for PathElem { |
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
f.write_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&[""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.name(),) |
|
{ |
|
(__arg0,) => |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
} |
|
pub struct LinkedPathNode<'a> { |
|
node: PathElem, |
|
next: LinkedPath<'a>, |
|
} |
|
#[automatically_derived] |
|
impl <'a> ::std::clone::Clone for LinkedPathNode<'a> { |
|
#[inline] |
|
fn clone(&self) -> LinkedPathNode<'a> { |
|
match *self { |
|
LinkedPathNode { |
|
node: ref __self_0_0, next: ref __self_0_1 } => |
|
LinkedPathNode{node: |
|
::std::clone::Clone::clone(&(*__self_0_0)), |
|
next: |
|
::std::clone::Clone::clone(&(*__self_0_1)),}, |
|
} |
|
} |
|
} |
|
pub struct LinkedPath<'a>(Option<&'a LinkedPathNode<'a>>); |
|
#[automatically_derived] |
|
impl <'a> ::std::clone::Clone for LinkedPath<'a> { |
|
#[inline] |
|
fn clone(&self) -> LinkedPath<'a> { |
|
match *self { |
|
LinkedPath(ref __self_0_0) => |
|
LinkedPath(::std::clone::Clone::clone(&(*__self_0_0))), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl <'a> ::std::marker::Copy for LinkedPath<'a> { } |
|
impl <'a> LinkedPath<'a> { |
|
pub fn empty() -> LinkedPath<'a> { LinkedPath(None) } |
|
pub fn from(node: &'a LinkedPathNode) -> LinkedPath<'a> { |
|
LinkedPath(Some(node)) |
|
} |
|
} |
|
impl <'a> Iterator for LinkedPath<'a> { |
|
type |
|
Item |
|
= |
|
PathElem; |
|
fn next(&mut self) -> Option<PathElem> { |
|
match self.0 { |
|
Some(node) => { *self = node.next; Some(node.node) } |
|
None => None, |
|
} |
|
} |
|
} |
|
/// The type of the iterator used by with_path. |
|
pub type PathElems<'a, 'b> = |
|
iter::Chain<iter::Cloned<slice::Iter<'a, PathElem>>, |
|
LinkedPath<'b>>; |
|
pub fn path_to_string<PI: Iterator<Item = PathElem>>(path: PI) |
|
-> String { |
|
let itr = token::get_ident_interner(); |
|
path.fold(String::new(), |mut s, e| { let e = itr.get(e.name()); |
|
if !s.is_empty() { s.push_str("::"); } |
|
s.push_str(&e[..]); s }) |
|
} |
|
pub enum Node<'ast> { |
|
NodeItem(&'ast Item), |
|
NodeForeignItem(&'ast ForeignItem), |
|
NodeTraitItem(&'ast TraitItem), |
|
NodeImplItem(&'ast ImplItem), |
|
NodeVariant(&'ast Variant), |
|
NodeExpr(&'ast Expr), |
|
NodeStmt(&'ast Stmt), |
|
NodeLocal(&'ast Pat), |
|
NodePat(&'ast Pat), |
|
NodeBlock(&'ast Block), |
|
|
|
/// NodeStructCtor represents a tuple struct. |
|
NodeStructCtor(&'ast VariantData), |
|
NodeLifetime(&'ast Lifetime), |
|
NodeTyParam(&'ast TyParam), |
|
} |
|
#[automatically_derived] |
|
impl <'ast> ::std::fmt::Debug for Node<'ast> { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&Node::NodeItem(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeItem").field(&&(*__self_0)).finish(), |
|
(&Node::NodeForeignItem(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeForeignItem").field(&&(*__self_0)).finish(), |
|
(&Node::NodeTraitItem(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeTraitItem").field(&&(*__self_0)).finish(), |
|
(&Node::NodeImplItem(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeImplItem").field(&&(*__self_0)).finish(), |
|
(&Node::NodeVariant(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeVariant").field(&&(*__self_0)).finish(), |
|
(&Node::NodeExpr(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeExpr").field(&&(*__self_0)).finish(), |
|
(&Node::NodeStmt(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeStmt").field(&&(*__self_0)).finish(), |
|
(&Node::NodeLocal(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeLocal").field(&&(*__self_0)).finish(), |
|
(&Node::NodePat(ref __self_0),) => |
|
__arg_0.debug_tuple("NodePat").field(&&(*__self_0)).finish(), |
|
(&Node::NodeBlock(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeBlock").field(&&(*__self_0)).finish(), |
|
(&Node::NodeStructCtor(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeStructCtor").field(&&(*__self_0)).finish(), |
|
(&Node::NodeLifetime(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeLifetime").field(&&(*__self_0)).finish(), |
|
(&Node::NodeTyParam(ref __self_0),) => |
|
__arg_0.debug_tuple("NodeTyParam").field(&&(*__self_0)).finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl <'ast> ::std::clone::Clone for Node<'ast> { |
|
#[inline] |
|
fn clone(&self) -> Node<'ast> { |
|
match (&*self,) { |
|
(&Node::NodeItem(ref __self_0),) => |
|
Node::NodeItem(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodeForeignItem(ref __self_0),) => |
|
Node::NodeForeignItem(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodeTraitItem(ref __self_0),) => |
|
Node::NodeTraitItem(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodeImplItem(ref __self_0),) => |
|
Node::NodeImplItem(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodeVariant(ref __self_0),) => |
|
Node::NodeVariant(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodeExpr(ref __self_0),) => |
|
Node::NodeExpr(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodeStmt(ref __self_0),) => |
|
Node::NodeStmt(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodeLocal(ref __self_0),) => |
|
Node::NodeLocal(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodePat(ref __self_0),) => |
|
Node::NodePat(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodeBlock(ref __self_0),) => |
|
Node::NodeBlock(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodeStructCtor(ref __self_0),) => |
|
Node::NodeStructCtor(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodeLifetime(ref __self_0),) => |
|
Node::NodeLifetime(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Node::NodeTyParam(ref __self_0),) => |
|
Node::NodeTyParam(::std::clone::Clone::clone(&(*__self_0))), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl <'ast> ::std::marker::Copy for Node<'ast> { } |
|
/// Represents an entry and its parent NodeID. |
|
/// The odd layout is to bring down the total size. |
|
pub enum MapEntry<'ast> { |
|
|
|
/// Placeholder for holes in the map. |
|
NotPresent, |
|
|
|
/// All the node types, with a parent ID. |
|
EntryItem(NodeId, &'ast Item), |
|
EntryForeignItem(NodeId, &'ast ForeignItem), |
|
EntryTraitItem(NodeId, &'ast TraitItem), |
|
EntryImplItem(NodeId, &'ast ImplItem), |
|
EntryVariant(NodeId, &'ast Variant), |
|
EntryExpr(NodeId, &'ast Expr), |
|
EntryStmt(NodeId, &'ast Stmt), |
|
EntryLocal(NodeId, &'ast Pat), |
|
EntryPat(NodeId, &'ast Pat), |
|
EntryBlock(NodeId, &'ast Block), |
|
EntryStructCtor(NodeId, &'ast VariantData), |
|
EntryLifetime(NodeId, &'ast Lifetime), |
|
EntryTyParam(NodeId, &'ast TyParam), |
|
|
|
/// Roots for node trees. |
|
RootCrate, |
|
RootInlinedParent(&'ast InlinedParent), |
|
} |
|
#[automatically_derived] |
|
impl <'ast> ::std::fmt::Debug for MapEntry<'ast> { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&MapEntry::NotPresent,) => |
|
__arg_0.debug_tuple("NotPresent").finish(), |
|
(&MapEntry::EntryItem(ref __self_0, ref __self_1),) => |
|
__arg_0.debug_tuple("EntryItem").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryForeignItem(ref __self_0, ref __self_1),) |
|
=> |
|
__arg_0.debug_tuple("EntryForeignItem").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryTraitItem(ref __self_0, ref __self_1),) |
|
=> |
|
__arg_0.debug_tuple("EntryTraitItem").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryImplItem(ref __self_0, ref __self_1),) => |
|
__arg_0.debug_tuple("EntryImplItem").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryVariant(ref __self_0, ref __self_1),) => |
|
__arg_0.debug_tuple("EntryVariant").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryExpr(ref __self_0, ref __self_1),) => |
|
__arg_0.debug_tuple("EntryExpr").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryStmt(ref __self_0, ref __self_1),) => |
|
__arg_0.debug_tuple("EntryStmt").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryLocal(ref __self_0, ref __self_1),) => |
|
__arg_0.debug_tuple("EntryLocal").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryPat(ref __self_0, ref __self_1),) => |
|
__arg_0.debug_tuple("EntryPat").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryBlock(ref __self_0, ref __self_1),) => |
|
__arg_0.debug_tuple("EntryBlock").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryStructCtor(ref __self_0, ref __self_1),) |
|
=> |
|
__arg_0.debug_tuple("EntryStructCtor").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryLifetime(ref __self_0, ref __self_1),) => |
|
__arg_0.debug_tuple("EntryLifetime").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::EntryTyParam(ref __self_0, ref __self_1),) => |
|
__arg_0.debug_tuple("EntryTyParam").field(&&(*__self_0)).field(&&(*__self_1)).finish(), |
|
(&MapEntry::RootCrate,) => |
|
__arg_0.debug_tuple("RootCrate").finish(), |
|
(&MapEntry::RootInlinedParent(ref __self_0),) => |
|
__arg_0.debug_tuple("RootInlinedParent").field(&&(*__self_0)).finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl <'ast> ::std::marker::Copy for MapEntry<'ast> { } |
|
impl <'ast> Clone for MapEntry<'ast> { |
|
fn clone(&self) -> MapEntry<'ast> { *self } |
|
} |
|
pub struct InlinedParent { |
|
path: Vec<PathElem>, |
|
ii: InlinedItem, |
|
} |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for InlinedParent { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match *self { |
|
InlinedParent { path: ref __self_0_0, ii: ref __self_0_1 } |
|
=> |
|
__arg_0.debug_struct("InlinedParent").field("path", |
|
&&(*__self_0_0)).field("ii", |
|
&&(*__self_0_1)).finish(), |
|
} |
|
} |
|
} |
|
impl <'ast> MapEntry<'ast> { |
|
fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> { |
|
match node { |
|
NodeItem(n) => EntryItem(p, n), |
|
NodeForeignItem(n) => EntryForeignItem(p, n), |
|
NodeTraitItem(n) => EntryTraitItem(p, n), |
|
NodeImplItem(n) => EntryImplItem(p, n), |
|
NodeVariant(n) => EntryVariant(p, n), |
|
NodeExpr(n) => EntryExpr(p, n), |
|
NodeStmt(n) => EntryStmt(p, n), |
|
NodeLocal(n) => EntryLocal(p, n), |
|
NodePat(n) => EntryPat(p, n), |
|
NodeBlock(n) => EntryBlock(p, n), |
|
NodeStructCtor(n) => EntryStructCtor(p, n), |
|
NodeLifetime(n) => EntryLifetime(p, n), |
|
NodeTyParam(n) => EntryTyParam(p, n), |
|
} |
|
} |
|
fn parent_node(self) -> Option<NodeId> { |
|
Some(match self { |
|
EntryItem(id, _) => id, |
|
EntryForeignItem(id, _) => id, |
|
EntryTraitItem(id, _) => id, |
|
EntryImplItem(id, _) => id, |
|
EntryVariant(id, _) => id, |
|
EntryExpr(id, _) => id, |
|
EntryStmt(id, _) => id, |
|
EntryLocal(id, _) => id, |
|
EntryPat(id, _) => id, |
|
EntryBlock(id, _) => id, |
|
EntryStructCtor(id, _) => id, |
|
EntryLifetime(id, _) => id, |
|
EntryTyParam(id, _) => id, |
|
_ => return None, |
|
}) |
|
} |
|
fn to_node(self) -> Option<Node<'ast>> { |
|
Some(match self { |
|
EntryItem(_, n) => NodeItem(n), |
|
EntryForeignItem(_, n) => NodeForeignItem(n), |
|
EntryTraitItem(_, n) => NodeTraitItem(n), |
|
EntryImplItem(_, n) => NodeImplItem(n), |
|
EntryVariant(_, n) => NodeVariant(n), |
|
EntryExpr(_, n) => NodeExpr(n), |
|
EntryStmt(_, n) => NodeStmt(n), |
|
EntryLocal(_, n) => NodeLocal(n), |
|
EntryPat(_, n) => NodePat(n), |
|
EntryBlock(_, n) => NodeBlock(n), |
|
EntryStructCtor(_, n) => NodeStructCtor(n), |
|
EntryLifetime(_, n) => NodeLifetime(n), |
|
EntryTyParam(_, n) => NodeTyParam(n), |
|
_ => return None, |
|
}) |
|
} |
|
} |
|
/// Stores a crate and any number of inlined items from other crates. |
|
pub struct Forest { |
|
pub krate: Crate, |
|
inlined_items: TypedArena<InlinedParent>, |
|
} |
|
impl Forest { |
|
pub fn new(krate: Crate) -> Forest { |
|
Forest{krate: krate, inlined_items: TypedArena::new(),} |
|
} |
|
pub fn krate<'ast>(&'ast self) -> &'ast Crate { &self.krate } |
|
} |
|
/// Represents a mapping from Node IDs to AST elements and their parent |
|
/// Node IDs |
|
pub struct Map<'ast> { |
|
/// The backing storage for all the AST nodes. |
|
pub forest: &'ast Forest, |
|
/// NodeIds are sequential integers from 0, so we can be |
|
/// super-compact by storing them in a vector. Not everything with |
|
/// a NodeId is in the map, but empirically the occupancy is about |
|
/// 75-80%, so there's not too much overhead (certainly less than |
|
/// a hashmap, since they (at the time of writing) have a maximum |
|
/// of 75% occupancy). |
|
/// |
|
/// Also, indexing is pretty quick when you've got a vector and |
|
/// plain old integers. |
|
map: RefCell<Vec<MapEntry<'ast>>>, |
|
definitions: RefCell<Definitions>, |
|
} |
|
#[automatically_derived] |
|
impl <'ast> ::std::clone::Clone for Map<'ast> { |
|
#[inline] |
|
fn clone(&self) -> Map<'ast> { |
|
match *self { |
|
Map { |
|
forest: ref __self_0_0, |
|
map: ref __self_0_1, |
|
definitions: ref __self_0_2 } => |
|
Map{forest: ::std::clone::Clone::clone(&(*__self_0_0)), |
|
map: ::std::clone::Clone::clone(&(*__self_0_1)), |
|
definitions: |
|
::std::clone::Clone::clone(&(*__self_0_2)),}, |
|
} |
|
} |
|
} |
|
impl <'ast> Map<'ast> { |
|
pub fn num_local_def_ids(&self) -> usize { |
|
self.definitions.borrow().len() |
|
} |
|
pub fn def_key(&self, def_id: DefId) -> DefKey { |
|
if !def_id.is_local() { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: def_id.is_local()", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, u32) |
|
= |
|
("src/librustc/front/map/mod.rs", |
|
275u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
self.definitions.borrow().def_key(def_id.index) |
|
} |
|
pub fn def_path_from_id(&self, id: NodeId) -> DefPath { |
|
self.def_path(self.local_def_id(id)) |
|
} |
|
pub fn def_path(&self, def_id: DefId) -> DefPath { |
|
if !def_id.is_local() { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: def_id.is_local()", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, u32) |
|
= |
|
("src/librustc/front/map/mod.rs", |
|
284u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
self.definitions.borrow().def_path(def_id.index) |
|
} |
|
pub fn local_def_id(&self, node: NodeId) -> DefId { |
|
self.opt_local_def_id(node).unwrap_or_else(|| { |
|
{ |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["local_def_id: no entry for `", |
|
"`, which has a map of `", |
|
"`"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&node, |
|
&self.find_entry(node)) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/front/map/mod.rs", |
|
290u32); |
|
&_FILE_LINE |
|
}) |
|
} }) |
|
} |
|
pub fn opt_local_def_id(&self, node: NodeId) -> Option<DefId> { |
|
self.definitions.borrow().opt_local_def_id(node) |
|
} |
|
pub fn as_local_node_id(&self, def_id: DefId) -> Option<NodeId> { |
|
self.definitions.borrow().as_local_node_id(def_id) |
|
} |
|
fn entry_count(&self) -> usize { self.map.borrow().len() } |
|
fn find_entry(&self, id: NodeId) -> Option<MapEntry<'ast>> { |
|
self.map.borrow().get(id as usize).cloned() |
|
} |
|
pub fn krate(&self) -> &'ast Crate { &self.forest.krate } |
|
/// Retrieve the Node corresponding to `id`, panicking if it cannot |
|
/// be found. |
|
pub fn get(&self, id: NodeId) -> Node<'ast> { |
|
match self.find(id) { |
|
Some(node) => node, |
|
None => { |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["couldn\'t find node id ", |
|
" in the AST map"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&id,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/mod.rs", |
|
320u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
pub fn get_if_local(&self, id: DefId) -> Option<Node<'ast>> { |
|
self.as_local_node_id(id).map(|id| self.get(id)) |
|
} |
|
/// Retrieve the Node corresponding to `id`, returning None if |
|
/// cannot be found. |
|
pub fn find(&self, id: NodeId) -> Option<Node<'ast>> { |
|
self.find_entry(id).and_then(|x| x.to_node()) |
|
} |
|
/// Similar to get_parent, returns the parent node id or id if there is no |
|
/// parent. |
|
/// This function returns the immediate parent in the AST, whereas get_parent |
|
/// returns the enclosing item. Note that this might not be the actual parent |
|
/// node in the AST - some kinds of nodes are not in the map and these will |
|
/// never appear as the parent_node. So you can always walk the parent_nodes |
|
/// from a node to the root of the ast (unless you get the same id back here |
|
/// that can happen if the id is not in the map itself or is just weird). |
|
pub fn get_parent_node(&self, id: NodeId) -> NodeId { |
|
self.find_entry(id).and_then(|x| |
|
x.parent_node()).unwrap_or(id) |
|
} |
|
/// Check if the node is an argument. An argument is a local variable whose |
|
/// immediate parent is an item or a closure. |
|
pub fn is_argument(&self, id: NodeId) -> bool { |
|
match self.find(id) { |
|
Some(NodeLocal(_)) => (), |
|
_ => return false, |
|
} |
|
match self.find(self.get_parent_node(id)) { |
|
Some(NodeItem(_)) | Some(NodeTraitItem(_)) | |
|
Some(NodeImplItem(_)) => true, |
|
Some(NodeExpr(e)) => { |
|
match e.node { ExprClosure(..) => true, _ => false, } |
|
} |
|
_ => false, |
|
} |
|
} |
|
/// If there is some error when walking the parents (e.g., a node does not |
|
/// have a parent in the map or a node can't be found), then we return the |
|
/// last good node id we found. Note that reaching the crate root (id == 0), |
|
/// is not an error, since items in the crate module have the crate root as |
|
/// parent. |
|
fn walk_parent_nodes<F>(&self, start_id: NodeId, found: F) |
|
-> Result<NodeId, NodeId> where F: Fn(&Node<'ast>) -> bool { |
|
let mut id = start_id; |
|
loop { |
|
let parent_node = self.get_parent_node(id); |
|
if parent_node == 0 { return Ok(0); } |
|
if parent_node == id { return Err(id); } |
|
let node = self.find_entry(parent_node); |
|
if node.is_none() { return Err(id); } |
|
let node = node.unwrap().to_node(); |
|
match node { |
|
Some(ref node) => { |
|
if found(node) { return Ok(parent_node); } |
|
} |
|
None => { return Err(parent_node); } |
|
} |
|
id = parent_node; |
|
} |
|
} |
|
/// Retrieve the NodeId for `id`'s parent item, or `id` itself if no |
|
/// parent item is in this map. The "parent item" is the closest parent node |
|
/// in the AST which is recorded by the map and is an item, either an item |
|
/// in a module, trait, or impl. |
|
pub fn get_parent(&self, id: NodeId) -> NodeId { |
|
match self.walk_parent_nodes(id, |
|
|node| |
|
match *node { |
|
NodeItem(_) | |
|
NodeForeignItem(_) | |
|
NodeTraitItem(_) | |
|
NodeImplItem(_) => true, |
|
_ => false, |
|
}) { |
|
Ok(id) => id, |
|
Err(id) => id, |
|
} |
|
} |
|
/// Returns the nearest enclosing scope. A scope is an item or block. |
|
/// FIXME it is not clear to me that all items qualify as scopes - statics |
|
/// and associated types probably shouldn't, for example. Behaviour in this |
|
/// regard should be expected to be highly unstable. |
|
pub fn get_enclosing_scope(&self, id: NodeId) -> Option<NodeId> { |
|
match self.walk_parent_nodes(id, |
|
|node| |
|
match *node { |
|
NodeItem(_) | |
|
NodeForeignItem(_) | |
|
NodeTraitItem(_) | |
|
NodeImplItem(_) | |
|
NodeBlock(_) => true, |
|
_ => false, |
|
}) { |
|
Ok(id) => Some(id), |
|
Err(_) => None, |
|
} |
|
} |
|
pub fn get_parent_did(&self, id: NodeId) -> DefId { |
|
let parent = self.get_parent(id); |
|
match self.find_entry(parent) { |
|
Some(RootInlinedParent(&InlinedParent { |
|
ii: II::TraitItem(did, _), .. })) |
|
=> did, |
|
Some(RootInlinedParent(&InlinedParent { |
|
ii: II::ImplItem(did, _), .. })) => |
|
did, |
|
_ => self.local_def_id(parent), |
|
} |
|
} |
|
pub fn get_foreign_abi(&self, id: NodeId) -> abi::Abi { |
|
let parent = self.get_parent(id); |
|
let abi = |
|
match self.find_entry(parent) { |
|
Some(EntryItem(_, i)) => { |
|
match i.node { |
|
ItemForeignMod(ref nm) => Some(nm.abi), |
|
_ => None, |
|
} |
|
} |
|
/// Wrong but OK, because the only inlined foreign items are intrinsics. |
|
Some(RootInlinedParent(_)) => |
|
Some(abi::RustIntrinsic), |
|
_ => None, |
|
}; |
|
match abi { |
|
Some(abi) => abi, |
|
None => { |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["expected foreign mod or inlined parent, found "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.node_to_string(parent),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/mod.rs", |
|
463u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
pub fn get_foreign_vis(&self, id: NodeId) -> Visibility { |
|
let vis = self.expect_foreign_item(id).vis; |
|
match self.find(self.get_parent(id)) { |
|
Some(NodeItem(i)) => vis.inherit_from(i.vis), |
|
_ => vis, |
|
} |
|
} |
|
pub fn expect_item(&self, id: NodeId) -> &'ast Item { |
|
match self.find(id) { |
|
Some(NodeItem(item)) => item, |
|
_ => { |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["expected item, found "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.node_to_string(id),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/mod.rs", |
|
479u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
pub fn expect_trait_item(&self, id: NodeId) -> &'ast TraitItem { |
|
match self.find(id) { |
|
Some(NodeTraitItem(item)) => item, |
|
_ => { |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["expected trait item, found "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.node_to_string(id),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/mod.rs", |
|
486u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
pub fn expect_struct(&self, id: NodeId) -> &'ast VariantData { |
|
match self.find(id) { |
|
Some(NodeItem(i)) => { |
|
match i.node { |
|
ItemStruct(ref struct_def, _) => struct_def, |
|
_ => { |
|
::std::rt::begin_unwind("struct ID bound to non-struct", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/mod.rs", |
|
495u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
Some(NodeVariant(variant)) => { |
|
if variant.node.data.is_struct() { |
|
&variant.node.data |
|
} else { |
|
{ |
|
::std::rt::begin_unwind("struct ID bound to enum variant that isn\'t struct-like", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/mod.rs", |
|
502u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
_ => { |
|
::std::rt::begin_unwind(::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["expected struct, found "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.node_to_string(id),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, u32) |
|
= |
|
("src/librustc/front/map/mod.rs", |
|
505u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
pub fn expect_variant(&self, id: NodeId) -> &'ast Variant { |
|
match self.find(id) { |
|
Some(NodeVariant(variant)) => variant, |
|
_ => { |
|
::std::rt::begin_unwind(::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["expected variant, found "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.node_to_string(id),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, u32) |
|
= |
|
("src/librustc/front/map/mod.rs", |
|
512u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
pub fn expect_foreign_item(&self, id: NodeId) |
|
-> &'ast ForeignItem { |
|
match self.find(id) { |
|
Some(NodeForeignItem(item)) => item, |
|
_ => { |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["expected foreign item, found "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.node_to_string(id),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/mod.rs", |
|
519u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
pub fn expect_expr(&self, id: NodeId) -> &'ast Expr { |
|
match self.find(id) { |
|
Some(NodeExpr(expr)) => expr, |
|
_ => { |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["expected expr, found "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.node_to_string(id),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/mod.rs", |
|
526u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
/// returns the name associated with the given NodeId's AST |
|
pub fn get_path_elem(&self, id: NodeId) -> PathElem { |
|
let node = self.get(id); |
|
match node { |
|
NodeItem(item) => { |
|
match item.node { |
|
ItemMod(_) | ItemForeignMod(_) => { |
|
PathMod(item.name) |
|
} |
|
_ => PathName(item.name), |
|
} |
|
} |
|
NodeForeignItem(i) => PathName(i.name), |
|
NodeImplItem(ii) => PathName(ii.name), |
|
NodeTraitItem(ti) => PathName(ti.name), |
|
NodeVariant(v) => PathName(v.node.name), |
|
NodeLifetime(lt) => PathName(lt.name), |
|
NodeTyParam(tp) => PathName(tp.name), |
|
NodeLocal(&Pat { node: PatIdent(_, l, _), .. }) => { |
|
PathName(l.node.name) |
|
} |
|
_ => { |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["no path elem for "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&node,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/front/map/mod.rs", |
|
551u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
pub fn with_path<T, F>(&self, id: NodeId, f: F) -> T where |
|
F: FnOnce(PathElems) -> T { |
|
self.with_path_next(id, LinkedPath::empty(), f) |
|
} |
|
pub fn path_to_string(&self, id: NodeId) -> String { |
|
self.with_path(id, |path| path_to_string(path)) |
|
} |
|
fn path_to_str_with_name(&self, id: NodeId, name: Name) |
|
-> String { |
|
self.with_path(id, |path| { |
|
path_to_string(path.chain(Some(PathName(name)))) |
|
}) |
|
} |
|
fn with_path_next<T, F>(&self, id: NodeId, next: LinkedPath, f: F) |
|
-> T where F: FnOnce(PathElems) -> T { |
|
let parent = self.get_parent(id); |
|
let parent = |
|
match self.find_entry(id) { |
|
Some(EntryForeignItem(..)) => { |
|
self.get_parent(parent) |
|
} |
|
Some(EntryStructCtor(..)) | Some(EntryExpr(..)) => { |
|
return self.with_path_next(parent, next, f); |
|
} |
|
_ => parent, |
|
}; |
|
if parent == id { |
|
match self.find_entry(id) { |
|
Some(RootInlinedParent(data)) => { |
|
f(data.path.iter().cloned().chain(next)) |
|
} |
|
_ => f([].iter().cloned().chain(next)), |
|
} |
|
} else { |
|
self.with_path_next(parent, |
|
LinkedPath::from(&LinkedPathNode{node: |
|
self.get_path_elem(id), |
|
next: |
|
next,}), |
|
f) |
|
} |
|
} |
|
/// Given a node ID, get a list of attributes associated with the AST |
|
/// corresponding to the Node ID |
|
pub fn attrs(&self, id: NodeId) -> &'ast [ast::Attribute] { |
|
let attrs = |
|
match self.find(id) { |
|
Some(NodeItem(i)) => Some(&i.attrs[..]), |
|
Some(NodeForeignItem(fi)) => Some(&fi.attrs[..]), |
|
Some(NodeTraitItem(ref ti)) => Some(&ti.attrs[..]), |
|
Some(NodeImplItem(ref ii)) => Some(&ii.attrs[..]), |
|
Some(NodeVariant(ref v)) => Some(&v.node.attrs[..]), |
|
Some(NodeStructCtor(_)) => { |
|
return self.attrs(self.get_parent(id)); |
|
} |
|
_ => None, |
|
}; |
|
attrs.unwrap_or(&[]) |
|
} |
|
/// Returns an iterator that yields the node id's with paths that |
|
/// match `parts`. (Requires `parts` is non-empty.) |
|
/// |
|
/// For example, if given `parts` equal to `["bar", "quux"]`, then |
|
/// the iterator will produce node id's for items with paths |
|
/// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and |
|
/// any other such items it can find in the map. |
|
pub fn nodes_matching_suffix<'a>(&'a self, parts: &'a [String]) |
|
-> NodesMatchingSuffix<'a, 'ast> { |
|
NodesMatchingSuffix{map: self, |
|
item_name: parts.last().unwrap(), |
|
in_which: &parts[..parts.len() - 1], |
|
idx: 0,} |
|
} |
|
pub fn opt_span(&self, id: NodeId) -> Option<Span> { |
|
let sp = |
|
match self.find(id) { |
|
Some(NodeItem(item)) => item.span, |
|
Some(NodeForeignItem(foreign_item)) => |
|
foreign_item.span, |
|
Some(NodeTraitItem(trait_method)) => |
|
trait_method.span, |
|
Some(NodeImplItem(ref impl_item)) => impl_item.span, |
|
Some(NodeVariant(variant)) => variant.span, |
|
Some(NodeExpr(expr)) => expr.span, |
|
Some(NodeStmt(stmt)) => stmt.span, |
|
Some(NodeLocal(pat)) => pat.span, |
|
Some(NodePat(pat)) => pat.span, |
|
Some(NodeBlock(block)) => block.span, |
|
Some(NodeStructCtor(_)) => |
|
self.expect_item(self.get_parent(id)).span, |
|
Some(NodeTyParam(ty_param)) => ty_param.span, |
|
_ => return None, |
|
}; |
|
Some(sp) |
|
} |
|
pub fn span(&self, id: NodeId) -> Span { |
|
self.opt_span(id).unwrap_or_else(|| { |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["AstMap.span: could not find span for id "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&id,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/front/map/mod.rs", |
|
659u32); |
|
&_FILE_LINE |
|
}) |
|
}) |
|
} |
|
pub fn span_if_local(&self, id: DefId) -> Option<Span> { |
|
self.as_local_node_id(id).map(|id| self.span(id)) |
|
} |
|
pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span { |
|
match self.as_local_node_id(def_id) { |
|
Some(node_id) => { |
|
self.opt_span(node_id).unwrap_or(fallback) |
|
} |
|
_ => { fallback } |
|
} |
|
} |
|
pub fn node_to_string(&self, id: NodeId) -> String { |
|
node_id_to_string(self, id, true) |
|
} |
|
pub fn node_to_user_string(&self, id: NodeId) -> String { |
|
node_id_to_string(self, id, false) |
|
} |
|
} |
|
pub struct NodesMatchingSuffix<'a, 'ast:'a> { |
|
map: &'a Map<'ast>, |
|
item_name: &'a String, |
|
in_which: &'a [String], |
|
idx: NodeId, |
|
} |
|
impl <'a, 'ast> NodesMatchingSuffix<'a, 'ast> { |
|
/// Returns true only if some suffix of the module path for parent |
|
/// matches `self.in_which`. |
|
/// |
|
/// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`; |
|
/// returns true if parent's path ends with the suffix |
|
/// `x_0::x_1::...::x_k`. |
|
fn suffix_matches(&self, parent: NodeId) -> bool { |
|
let mut cursor = parent; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(self.in_which.iter().rev()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(part) => { |
|
let (mod_id, mod_name) = |
|
match find_first_mod_parent(self.map, |
|
cursor) |
|
{ |
|
None => return false, |
|
Some((node_id, name)) => |
|
(node_id, name), |
|
}; |
|
if &part[..] != mod_name.as_str() { |
|
return false; |
|
} |
|
cursor = self.map.get_parent(mod_id); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
return true; |
|
fn find_first_mod_parent<'a>(map: &'a Map, mut id: NodeId) |
|
-> Option<(NodeId, Name)> { |
|
loop { |
|
match map.find(id) { |
|
None => return None, |
|
Some(NodeItem(item)) if item_is_mod(&*item) => |
|
return Some((id, item.name)), |
|
_ => { } |
|
} |
|
let parent = map.get_parent(id); |
|
if parent == id { return None } |
|
id = parent; |
|
} |
|
fn item_is_mod(item: &Item) -> bool { |
|
match item.node { ItemMod(_) => true, _ => false, } |
|
} |
|
} |
|
} |
|
fn matches_names(&self, parent_of_n: NodeId, name: Name) -> bool { |
|
name.as_str() == &self.item_name[..] && |
|
self.suffix_matches(parent_of_n) |
|
} |
|
} |
|
impl <'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> { |
|
type |
|
Item |
|
= |
|
NodeId; |
|
fn next(&mut self) -> Option<NodeId> { |
|
loop { |
|
let idx = self.idx; |
|
if idx as usize >= self.map.entry_count() { return None; } |
|
self.idx += 1; |
|
let name = |
|
match self.map.find_entry(idx) { |
|
Some(EntryItem(_, n)) => n.name(), |
|
Some(EntryForeignItem(_, n)) => n.name(), |
|
Some(EntryTraitItem(_, n)) => n.name(), |
|
Some(EntryImplItem(_, n)) => n.name(), |
|
Some(EntryVariant(_, n)) => n.name(), |
|
_ => continue , |
|
}; |
|
if self.matches_names(self.map.get_parent(idx), name) { |
|
return Some(idx) |
|
} |
|
} |
|
} |
|
} |
|
trait Named { |
|
fn name(&self) |
|
-> Name; |
|
} |
|
impl <T: Named> Named for Spanned<T> { |
|
fn name(&self) -> Name { self.node.name() } |
|
} |
|
impl Named for Item { |
|
fn name(&self) -> Name { self.name } |
|
} |
|
impl Named for ForeignItem { |
|
fn name(&self) -> Name { self.name } |
|
} |
|
impl Named for Variant_ { |
|
fn name(&self) -> Name { self.name } |
|
} |
|
impl Named for TraitItem { |
|
fn name(&self) -> Name { self.name } |
|
} |
|
impl Named for ImplItem { |
|
fn name(&self) -> Name { self.name } |
|
} |
|
pub trait FoldOps { |
|
fn new_id(&self, id: NodeId) -> NodeId { id } |
|
fn new_def_id(&self, def_id: DefId) -> DefId { def_id } |
|
fn new_span(&self, span: Span) -> Span { span } |
|
} |
|
/// A Folder that updates IDs and Span's according to fold_ops. |
|
struct IdAndSpanUpdater<F> { |
|
fold_ops: F, |
|
} |
|
impl <F: FoldOps> Folder for IdAndSpanUpdater<F> { |
|
fn new_id(&mut self, id: NodeId) -> NodeId { |
|
self.fold_ops.new_id(id) |
|
} |
|
fn new_span(&mut self, span: Span) -> Span { |
|
self.fold_ops.new_span(span) |
|
} |
|
} |
|
pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> { |
|
let (map, definitions) = |
|
{ |
|
let mut collector = NodeCollector::root(&forest.krate); |
|
intravisit::walk_crate(&mut collector, &forest.krate); |
|
(collector.map, collector.definitions) |
|
}; |
|
if { |
|
let lvl = ::log::DEBUG; |
|
(lvl != ::log::DEBUG || false) && lvl <= ::log::log_level() |
|
&& ::log::mod_enabled(lvl, "rustc::front::map") |
|
} { |
|
let (entries_less_1, _) = |
|
map.iter().filter(|&x| { |
|
match *x { |
|
NotPresent => false, |
|
_ => true, |
|
} |
|
}).enumerate().last().expect("AST map was empty after folding?"); |
|
let entries = entries_less_1 + 1; |
|
let vector_length = map.len(); |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 830u32, |
|
file: |
|
"src/librustc/front/map/mod.rs", |
|
module_path: |
|
"rustc::front::map",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::front::map") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1_formatted({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["The AST map has ", |
|
" entries with a maximum of ", |
|
": occupancy ", |
|
"%"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&entries, |
|
&vector_length, |
|
&((entries |
|
as |
|
f64 |
|
/ |
|
vector_length |
|
as |
|
f64) |
|
* |
|
100.)) |
|
{ |
|
(__arg0, |
|
__arg1, |
|
__arg2) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg2, |
|
::std::fmt::Display::fmt)], |
|
}, |
|
{ |
|
static __STATIC_FMTARGS: |
|
&'static [::std::fmt::rt::v1::Argument] |
|
= |
|
&[::std::fmt::rt::v1::Argument{position: |
|
::std::fmt::rt::v1::Position::Next, |
|
format: |
|
::std::fmt::rt::v1::FormatSpec{fill: |
|
' ', |
|
align: |
|
::std::fmt::rt::v1::Alignment::Unknown, |
|
flags: |
|
0u32, |
|
precision: |
|
::std::fmt::rt::v1::Count::Implied, |
|
width: |
|
::std::fmt::rt::v1::Count::Implied,},}, |
|
::std::fmt::rt::v1::Argument{position: |
|
::std::fmt::rt::v1::Position::Next, |
|
format: |
|
::std::fmt::rt::v1::FormatSpec{fill: |
|
' ', |
|
align: |
|
::std::fmt::rt::v1::Alignment::Unknown, |
|
flags: |
|
0u32, |
|
precision: |
|
::std::fmt::rt::v1::Count::Implied, |
|
width: |
|
::std::fmt::rt::v1::Count::Implied,},}, |
|
::std::fmt::rt::v1::Argument{position: |
|
::std::fmt::rt::v1::Position::Next, |
|
format: |
|
::std::fmt::rt::v1::FormatSpec{fill: |
|
' ', |
|
align: |
|
::std::fmt::rt::v1::Alignment::Unknown, |
|
flags: |
|
0u32, |
|
precision: |
|
::std::fmt::rt::v1::Count::Is(1usize), |
|
width: |
|
::std::fmt::rt::v1::Count::Implied,},}]; |
|
__STATIC_FMTARGS |
|
})) |
|
} |
|
} |
|
}; |
|
} |
|
Map{forest: forest, |
|
map: RefCell::new(map), |
|
definitions: RefCell::new(definitions),} |
|
} |
|
/// Used for items loaded from external crate that are being inlined into this |
|
/// crate. The `path` should be the path to the item but should not include |
|
/// the item itself. |
|
pub fn map_decoded_item<'ast, |
|
F: FoldOps>(map: &Map<'ast>, |
|
path: Vec<PathElem>, |
|
def_path: DefPath, |
|
ii: InlinedItem, fold_ops: F) |
|
-> &'ast InlinedItem { |
|
let mut fld = IdAndSpanUpdater{fold_ops: fold_ops,}; |
|
let ii = |
|
match ii { |
|
II::Item(i) => II::Item(i.map(|i| fld.fold_item(i))), |
|
II::TraitItem(d, ti) => { |
|
II::TraitItem(fld.fold_ops.new_def_id(d), |
|
fld.fold_trait_item(ti)) |
|
} |
|
II::ImplItem(d, ii) => { |
|
II::ImplItem(fld.fold_ops.new_def_id(d), |
|
fld.fold_impl_item(ii)) |
|
} |
|
II::Foreign(i) => II::Foreign(fld.fold_foreign_item(i)), |
|
}; |
|
let ii_parent = |
|
map.forest.inlined_items.alloc(InlinedParent{path: path, |
|
ii: ii,}); |
|
let ii_parent_id = fld.new_id(DUMMY_NODE_ID); |
|
let mut collector = |
|
NodeCollector::extend(map.krate(), ii_parent, ii_parent_id, |
|
def_path, |
|
mem::replace(&mut *map.map.borrow_mut(), |
|
<[_]>::into_vec(::std::boxed::Box::new([]))), |
|
mem::replace(&mut *map.definitions.borrow_mut(), |
|
Definitions::new())); |
|
ii_parent.ii.visit(&mut collector); |
|
*map.map.borrow_mut() = collector.map; |
|
*map.definitions.borrow_mut() = collector.definitions; |
|
&ii_parent.ii |
|
} |
|
pub trait NodePrinter { |
|
fn print_node(&mut self, node: &Node) |
|
-> io::Result<()>; |
|
} |
|
impl <'a> NodePrinter for pprust::State<'a> { |
|
fn print_node(&mut self, node: &Node) -> io::Result<()> { |
|
match *node { |
|
NodeItem(a) => self.print_item(&*a), |
|
NodeForeignItem(a) => self.print_foreign_item(&*a), |
|
NodeTraitItem(a) => self.print_trait_item(a), |
|
NodeImplItem(a) => self.print_impl_item(a), |
|
NodeVariant(a) => self.print_variant(&*a), |
|
NodeExpr(a) => self.print_expr(&*a), |
|
NodeStmt(a) => self.print_stmt(&*a), |
|
NodePat(a) => self.print_pat(&*a), |
|
NodeBlock(a) => self.print_block(&*a), |
|
NodeLifetime(a) => self.print_lifetime(&*a), |
|
NodeTyParam(_) => { |
|
::std::rt::begin_unwind("cannot print TyParam", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, u32) |
|
= |
|
("src/librustc/front/map/mod.rs", |
|
903u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
NodeLocal(_) => { |
|
::std::rt::begin_unwind("cannot print isolated Local", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, u32) |
|
= |
|
("src/librustc/front/map/mod.rs", |
|
907u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
NodeStructCtor(_) => { |
|
::std::rt::begin_unwind("cannot print isolated StructCtor", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, u32) |
|
= |
|
("src/librustc/front/map/mod.rs", |
|
908u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) |
|
-> String { |
|
let id_str = |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&[" (id=", |
|
")"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&id,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})); |
|
let id_str = if include_id { &id_str[..] } else { "" }; |
|
match map.find(id) { |
|
Some(NodeItem(item)) => { |
|
let path_str = map.path_to_str_with_name(id, item.name); |
|
let item_str = |
|
match item.node { |
|
ItemExternCrate(..) => "extern crate", |
|
ItemUse(..) => "use", |
|
ItemStatic(..) => "static", |
|
ItemConst(..) => "const", |
|
ItemFn(..) => "fn", |
|
ItemMod(..) => "mod", |
|
ItemForeignMod(..) => "foreign mod", |
|
ItemTy(..) => "ty", |
|
ItemEnum(..) => "enum", |
|
ItemStruct(..) => "struct", |
|
ItemTrait(..) => "trait", |
|
ItemImpl(..) => "impl", |
|
ItemDefaultImpl(..) => "default impl", |
|
}; |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["", |
|
" ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&item_str, |
|
&path_str, |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1, |
|
__arg2) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg2, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
Some(NodeForeignItem(item)) => { |
|
let path_str = map.path_to_str_with_name(id, item.name); |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["foreign item ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&path_str, |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
Some(NodeImplItem(ii)) => { |
|
match ii.node { |
|
ImplItemKind::Const(..) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["assoc const ", |
|
" in ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&ii.name, |
|
&map.path_to_string(id), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1, |
|
__arg2) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg2, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
ImplItemKind::Method(..) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["method ", |
|
" in ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&ii.name, |
|
&map.path_to_string(id), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1, |
|
__arg2) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg2, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
ImplItemKind::Type(_) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["assoc type ", |
|
" in ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&ii.name, |
|
&map.path_to_string(id), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1, |
|
__arg2) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg2, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
} |
|
} |
|
Some(NodeTraitItem(ti)) => { |
|
let kind = |
|
match ti.node { |
|
ConstTraitItem(..) => "assoc constant", |
|
MethodTraitItem(..) => "trait method", |
|
TypeTraitItem(..) => "assoc type", |
|
}; |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["", |
|
" ", |
|
" in ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&kind, |
|
&ti.name, |
|
&map.path_to_string(id), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1, |
|
__arg2, |
|
__arg3) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg2, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg3, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
Some(NodeVariant(ref variant)) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["variant ", |
|
" in ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&variant.node.name, |
|
&map.path_to_string(id), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1, |
|
__arg2) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg2, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
Some(NodeExpr(ref expr)) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["expr ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&pprust::expr_to_string(&**expr), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
Some(NodeStmt(ref stmt)) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["stmt ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&pprust::stmt_to_string(&**stmt), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
Some(NodeLocal(ref pat)) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["local ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&pprust::pat_to_string(&**pat), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
Some(NodePat(ref pat)) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["pat ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&pprust::pat_to_string(&**pat), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
Some(NodeBlock(ref block)) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["block ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&pprust::block_to_string(&**block), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
Some(NodeStructCtor(_)) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["struct_ctor ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&map.path_to_string(id), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
Some(NodeLifetime(ref l)) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["lifetime ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&pprust::lifetime_to_string(&**l), |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
Some(NodeTyParam(ref ty_param)) => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["typaram ", |
|
""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&ty_param, |
|
&id_str) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
None => { |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["unknown node"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&id_str,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
} |
|
} |
|
} |
|
} |
|
pub mod middle { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
pub mod astconv_util { |
|
/*! |
|
* 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. |
|
*/ |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
use middle::def; |
|
use middle::ty::{self, Ty}; |
|
use syntax::codemap::Span; |
|
use rustc_front::hir as ast; |
|
pub fn prohibit_type_params(tcx: &ty::ctxt, |
|
segments: &[ast::PathSegment]) { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(segments) { |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(segment) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(segment.parameters.types()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(typ) |
|
=> { |
|
{ |
|
(); |
|
tcx.sess.span_err_with_code(typ.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["type parameters are not allowed on this type"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0109") |
|
}; |
|
break ; |
|
} |
|
::std::option::Option::None |
|
=> break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(segment.parameters.lifetimes()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(lifetime) |
|
=> { |
|
{ |
|
(); |
|
tcx.sess.span_err_with_code(lifetime.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["lifetime parameters are not allowed on this type"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0110") |
|
}; |
|
break ; |
|
} |
|
::std::option::Option::None |
|
=> break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(segment.parameters.bindings()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(binding) |
|
=> { |
|
prohibit_projection(tcx, |
|
binding.span); |
|
break ; |
|
} |
|
::std::option::Option::None |
|
=> break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
pub fn prohibit_projection(tcx: &ty::ctxt, span: Span) { |
|
{ |
|
(); |
|
tcx.sess.span_err_with_code(span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["associated type bindings are not allowed here"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0229") |
|
}; |
|
} |
|
pub fn prim_ty_to_ty<'tcx>(tcx: &ty::ctxt<'tcx>, |
|
segments: &[ast::PathSegment], |
|
nty: ast::PrimTy) -> Ty<'tcx> { |
|
prohibit_type_params(tcx, segments); |
|
match nty { |
|
ast::TyBool => tcx.types.bool, |
|
ast::TyChar => tcx.types.char, |
|
ast::TyInt(it) => tcx.mk_mach_int(it), |
|
ast::TyUint(uit) => tcx.mk_mach_uint(uit), |
|
ast::TyFloat(ft) => tcx.mk_mach_float(ft), |
|
ast::TyStr => tcx.mk_str(), |
|
} |
|
} |
|
/// If a type in the AST is a primitive type, return the ty::Ty corresponding |
|
/// to it. |
|
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(None, ref path) => { |
|
let def = |
|
match tcx.def_map.borrow().get(&ast_ty.id) { |
|
None => { |
|
tcx.sess.span_bug(ast_ty.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["unbound path "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&path,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt)], |
|
}))) |
|
} |
|
Some(d) => d.full_def(), |
|
}; |
|
match def { |
|
def::DefPrimTy(nty) => { |
|
Some(prim_ty_to_ty(tcx, &path.segments, nty)) |
|
} |
|
_ => { None } |
|
} |
|
} |
|
_ => { None } |
|
} |
|
} |
|
} |
|
pub mod expr_use_visitor { |
|
//! A different sort of visitor for walking fn bodies. Unlike the |
|
//! normal visitor, which just walks the entire body in one shot, the |
|
//! `ExprUseVisitor` determines how expressions are being used. |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
pub use self::MutateMode::*; |
|
pub use self::LoanCause::*; |
|
pub use self::ConsumeMode::*; |
|
pub use self::MoveReason::*; |
|
pub use self::MatchMode::*; |
|
use self::TrackMatchMode::*; |
|
use self::OverloadedCallType::*; |
|
use middle::{def, pat_util}; |
|
use middle::def_id::{DefId}; |
|
use middle::infer; |
|
use middle::mem_categorization as mc; |
|
use middle::ty; |
|
use middle::ty::adjustment; |
|
use rustc_front::hir; |
|
use syntax::ast; |
|
use syntax::ptr::P; |
|
use syntax::codemap::Span; |
|
/// This trait defines the callbacks you can expect to receive when |
|
/// employing the ExprUseVisitor. |
|
pub trait Delegate<'tcx> { |
|
fn consume(&mut self, consume_id: ast::NodeId, consume_span: Span, |
|
cmt: mc::cmt<'tcx>, mode: ConsumeMode); |
|
fn matched_pat(&mut self, matched_pat: &hir::Pat, |
|
cmt: mc::cmt<'tcx>, mode: MatchMode); |
|
fn consume_pat(&mut self, consume_pat: &hir::Pat, |
|
cmt: mc::cmt<'tcx>, mode: ConsumeMode); |
|
fn borrow(&mut self, borrow_id: ast::NodeId, borrow_span: Span, |
|
cmt: mc::cmt<'tcx>, loan_region: ty::Region, |
|
bk: ty::BorrowKind, loan_cause: LoanCause); |
|
fn decl_without_init(&mut self, id: ast::NodeId, span: Span); |
|
fn mutate(&mut self, assignment_id: ast::NodeId, |
|
assignment_span: Span, assignee_cmt: mc::cmt<'tcx>, |
|
mode: MutateMode); |
|
} |
|
pub enum LoanCause { |
|
ClosureCapture(Span), |
|
AddrOf, |
|
AutoRef, |
|
AutoUnsafe, |
|
RefBinding, |
|
OverloadedOperator, |
|
ClosureInvocation, |
|
ForLoop, |
|
MatchDiscriminant, |
|
} |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for LoanCause { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&LoanCause::ClosureCapture(ref __self_0),) => |
|
__arg_0.debug_tuple("ClosureCapture").field(&&(*__self_0)).finish(), |
|
(&LoanCause::AddrOf,) => |
|
__arg_0.debug_tuple("AddrOf").finish(), |
|
(&LoanCause::AutoRef,) => |
|
__arg_0.debug_tuple("AutoRef").finish(), |
|
(&LoanCause::AutoUnsafe,) => |
|
__arg_0.debug_tuple("AutoUnsafe").finish(), |
|
(&LoanCause::RefBinding,) => |
|
__arg_0.debug_tuple("RefBinding").finish(), |
|
(&LoanCause::OverloadedOperator,) => |
|
__arg_0.debug_tuple("OverloadedOperator").finish(), |
|
(&LoanCause::ClosureInvocation,) => |
|
__arg_0.debug_tuple("ClosureInvocation").finish(), |
|
(&LoanCause::ForLoop,) => |
|
__arg_0.debug_tuple("ForLoop").finish(), |
|
(&LoanCause::MatchDiscriminant,) => |
|
__arg_0.debug_tuple("MatchDiscriminant").finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for LoanCause { |
|
#[inline] |
|
fn eq(&self, __arg_0: &LoanCause) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&LoanCause::ClosureCapture(ref __self_0), |
|
&LoanCause::ClosureCapture(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&LoanCause::AddrOf, &LoanCause::AddrOf) => true, |
|
(&LoanCause::AutoRef, &LoanCause::AutoRef) => |
|
true, |
|
(&LoanCause::AutoUnsafe, &LoanCause::AutoUnsafe) |
|
=> true, |
|
(&LoanCause::RefBinding, &LoanCause::RefBinding) |
|
=> true, |
|
(&LoanCause::OverloadedOperator, |
|
&LoanCause::OverloadedOperator) => true, |
|
(&LoanCause::ClosureInvocation, |
|
&LoanCause::ClosureInvocation) => true, |
|
(&LoanCause::ForLoop, &LoanCause::ForLoop) => |
|
true, |
|
(&LoanCause::MatchDiscriminant, |
|
&LoanCause::MatchDiscriminant) => true, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &LoanCause) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&LoanCause::ClosureCapture(ref __self_0), |
|
&LoanCause::ClosureCapture(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&LoanCause::AddrOf, &LoanCause::AddrOf) => false, |
|
(&LoanCause::AutoRef, &LoanCause::AutoRef) => |
|
false, |
|
(&LoanCause::AutoUnsafe, &LoanCause::AutoUnsafe) |
|
=> false, |
|
(&LoanCause::RefBinding, &LoanCause::RefBinding) |
|
=> false, |
|
(&LoanCause::OverloadedOperator, |
|
&LoanCause::OverloadedOperator) => false, |
|
(&LoanCause::ClosureInvocation, |
|
&LoanCause::ClosureInvocation) => false, |
|
(&LoanCause::ForLoop, &LoanCause::ForLoop) => |
|
false, |
|
(&LoanCause::MatchDiscriminant, |
|
&LoanCause::MatchDiscriminant) => false, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for LoanCause { |
|
#[inline] |
|
fn clone(&self) -> LoanCause { |
|
match (&*self,) { |
|
(&LoanCause::ClosureCapture(ref __self_0),) => |
|
LoanCause::ClosureCapture(::std::clone::Clone::clone(&(*__self_0))), |
|
(&LoanCause::AddrOf,) => LoanCause::AddrOf, |
|
(&LoanCause::AutoRef,) => LoanCause::AutoRef, |
|
(&LoanCause::AutoUnsafe,) => LoanCause::AutoUnsafe, |
|
(&LoanCause::RefBinding,) => LoanCause::RefBinding, |
|
(&LoanCause::OverloadedOperator,) => |
|
LoanCause::OverloadedOperator, |
|
(&LoanCause::ClosureInvocation,) => |
|
LoanCause::ClosureInvocation, |
|
(&LoanCause::ForLoop,) => LoanCause::ForLoop, |
|
(&LoanCause::MatchDiscriminant,) => |
|
LoanCause::MatchDiscriminant, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for LoanCause { } |
|
pub enum ConsumeMode { Copy, Move(MoveReason), } |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for ConsumeMode { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&ConsumeMode::Copy,) => |
|
__arg_0.debug_tuple("Copy").finish(), |
|
(&ConsumeMode::Move(ref __self_0),) => |
|
__arg_0.debug_tuple("Move").field(&&(*__self_0)).finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for ConsumeMode { |
|
#[inline] |
|
fn eq(&self, __arg_0: &ConsumeMode) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&ConsumeMode::Copy, &ConsumeMode::Copy) => true, |
|
(&ConsumeMode::Move(ref __self_0), |
|
&ConsumeMode::Move(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &ConsumeMode) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&ConsumeMode::Copy, &ConsumeMode::Copy) => false, |
|
(&ConsumeMode::Move(ref __self_0), |
|
&ConsumeMode::Move(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for ConsumeMode { |
|
#[inline] |
|
fn clone(&self) -> ConsumeMode { |
|
match (&*self,) { |
|
(&ConsumeMode::Copy,) => ConsumeMode::Copy, |
|
(&ConsumeMode::Move(ref __self_0),) => |
|
ConsumeMode::Move(::std::clone::Clone::clone(&(*__self_0))), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for ConsumeMode { } |
|
pub enum MoveReason { DirectRefMove, PatBindingMove, CaptureMove, } |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for MoveReason { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&MoveReason::DirectRefMove,) => |
|
__arg_0.debug_tuple("DirectRefMove").finish(), |
|
(&MoveReason::PatBindingMove,) => |
|
__arg_0.debug_tuple("PatBindingMove").finish(), |
|
(&MoveReason::CaptureMove,) => |
|
__arg_0.debug_tuple("CaptureMove").finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for MoveReason { |
|
#[inline] |
|
fn eq(&self, __arg_0: &MoveReason) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&MoveReason::DirectRefMove, |
|
&MoveReason::DirectRefMove) => true, |
|
(&MoveReason::PatBindingMove, |
|
&MoveReason::PatBindingMove) => true, |
|
(&MoveReason::CaptureMove, |
|
&MoveReason::CaptureMove) => true, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &MoveReason) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&MoveReason::DirectRefMove, |
|
&MoveReason::DirectRefMove) => false, |
|
(&MoveReason::PatBindingMove, |
|
&MoveReason::PatBindingMove) => false, |
|
(&MoveReason::CaptureMove, |
|
&MoveReason::CaptureMove) => false, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for MoveReason { |
|
#[inline] |
|
fn clone(&self) -> MoveReason { |
|
match (&*self,) { |
|
(&MoveReason::DirectRefMove,) => |
|
MoveReason::DirectRefMove, |
|
(&MoveReason::PatBindingMove,) => |
|
MoveReason::PatBindingMove, |
|
(&MoveReason::CaptureMove,) => MoveReason::CaptureMove, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for MoveReason { } |
|
pub enum MatchMode { |
|
NonBindingMatch, |
|
BorrowingMatch, |
|
CopyingMatch, |
|
MovingMatch, |
|
} |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for MatchMode { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&MatchMode::NonBindingMatch,) => |
|
__arg_0.debug_tuple("NonBindingMatch").finish(), |
|
(&MatchMode::BorrowingMatch,) => |
|
__arg_0.debug_tuple("BorrowingMatch").finish(), |
|
(&MatchMode::CopyingMatch,) => |
|
__arg_0.debug_tuple("CopyingMatch").finish(), |
|
(&MatchMode::MovingMatch,) => |
|
__arg_0.debug_tuple("MovingMatch").finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for MatchMode { |
|
#[inline] |
|
fn eq(&self, __arg_0: &MatchMode) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&MatchMode::NonBindingMatch, |
|
&MatchMode::NonBindingMatch) => true, |
|
(&MatchMode::BorrowingMatch, |
|
&MatchMode::BorrowingMatch) => true, |
|
(&MatchMode::CopyingMatch, |
|
&MatchMode::CopyingMatch) => true, |
|
(&MatchMode::MovingMatch, &MatchMode::MovingMatch) |
|
=> true, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &MatchMode) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&MatchMode::NonBindingMatch, |
|
&MatchMode::NonBindingMatch) => false, |
|
(&MatchMode::BorrowingMatch, |
|
&MatchMode::BorrowingMatch) => false, |
|
(&MatchMode::CopyingMatch, |
|
&MatchMode::CopyingMatch) => false, |
|
(&MatchMode::MovingMatch, &MatchMode::MovingMatch) |
|
=> false, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for MatchMode { |
|
#[inline] |
|
fn clone(&self) -> MatchMode { |
|
match (&*self,) { |
|
(&MatchMode::NonBindingMatch,) => |
|
MatchMode::NonBindingMatch, |
|
(&MatchMode::BorrowingMatch,) => |
|
MatchMode::BorrowingMatch, |
|
(&MatchMode::CopyingMatch,) => MatchMode::CopyingMatch, |
|
(&MatchMode::MovingMatch,) => MatchMode::MovingMatch, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for MatchMode { } |
|
enum TrackMatchMode { Unknown, Definite(MatchMode), Conflicting, } |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for TrackMatchMode { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&TrackMatchMode::Unknown,) => |
|
__arg_0.debug_tuple("Unknown").finish(), |
|
(&TrackMatchMode::Definite(ref __self_0),) => |
|
__arg_0.debug_tuple("Definite").field(&&(*__self_0)).finish(), |
|
(&TrackMatchMode::Conflicting,) => |
|
__arg_0.debug_tuple("Conflicting").finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for TrackMatchMode { |
|
#[inline] |
|
fn eq(&self, __arg_0: &TrackMatchMode) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&TrackMatchMode::Unknown, |
|
&TrackMatchMode::Unknown) => true, |
|
(&TrackMatchMode::Definite(ref __self_0), |
|
&TrackMatchMode::Definite(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&TrackMatchMode::Conflicting, |
|
&TrackMatchMode::Conflicting) => true, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &TrackMatchMode) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&TrackMatchMode::Unknown, |
|
&TrackMatchMode::Unknown) => false, |
|
(&TrackMatchMode::Definite(ref __self_0), |
|
&TrackMatchMode::Definite(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&TrackMatchMode::Conflicting, |
|
&TrackMatchMode::Conflicting) => false, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for TrackMatchMode { |
|
#[inline] |
|
fn clone(&self) -> TrackMatchMode { |
|
match (&*self,) { |
|
(&TrackMatchMode::Unknown,) => TrackMatchMode::Unknown, |
|
(&TrackMatchMode::Definite(ref __self_0),) => |
|
TrackMatchMode::Definite(::std::clone::Clone::clone(&(*__self_0))), |
|
(&TrackMatchMode::Conflicting,) => |
|
TrackMatchMode::Conflicting, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for TrackMatchMode { } |
|
impl TrackMatchMode { |
|
fn lub(&mut self, mode: MatchMode) { |
|
*self = |
|
match (*self, mode) { |
|
(Unknown, new) => Definite(new), |
|
(Definite(old), new) if old == new => Definite(old), |
|
(Definite(old), NonBindingMatch) => Definite(old), |
|
(Definite(NonBindingMatch), new) => Definite(new), |
|
(Definite(old), CopyingMatch) => Definite(old), |
|
(Definite(CopyingMatch), new) => Definite(new), |
|
(Definite(_), _) => Conflicting, |
|
(Conflicting, _) => *self, |
|
}; |
|
} |
|
fn match_mode(&self) -> MatchMode { |
|
match *self { |
|
Unknown => NonBindingMatch, |
|
Definite(mode) => mode, |
|
Conflicting => { MovingMatch } |
|
} |
|
} |
|
} |
|
pub enum MutateMode { Init, JustWrite, WriteAndRead, } |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for MutateMode { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&MutateMode::Init,) => |
|
__arg_0.debug_tuple("Init").finish(), |
|
(&MutateMode::JustWrite,) => |
|
__arg_0.debug_tuple("JustWrite").finish(), |
|
(&MutateMode::WriteAndRead,) => |
|
__arg_0.debug_tuple("WriteAndRead").finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for MutateMode { |
|
#[inline] |
|
fn eq(&self, __arg_0: &MutateMode) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&MutateMode::Init, &MutateMode::Init) => true, |
|
(&MutateMode::JustWrite, &MutateMode::JustWrite) |
|
=> true, |
|
(&MutateMode::WriteAndRead, |
|
&MutateMode::WriteAndRead) => true, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &MutateMode) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&MutateMode::Init, &MutateMode::Init) => false, |
|
(&MutateMode::JustWrite, &MutateMode::JustWrite) |
|
=> false, |
|
(&MutateMode::WriteAndRead, |
|
&MutateMode::WriteAndRead) => false, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for MutateMode { |
|
#[inline] |
|
fn clone(&self) -> MutateMode { |
|
match (&*self,) { |
|
(&MutateMode::Init,) => MutateMode::Init, |
|
(&MutateMode::JustWrite,) => MutateMode::JustWrite, |
|
(&MutateMode::WriteAndRead,) => MutateMode::WriteAndRead, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for MutateMode { } |
|
enum OverloadedCallType { |
|
FnOverloadedCall, |
|
FnMutOverloadedCall, |
|
FnOnceOverloadedCall, |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for OverloadedCallType { |
|
#[inline] |
|
fn clone(&self) -> OverloadedCallType { |
|
match (&*self,) { |
|
(&OverloadedCallType::FnOverloadedCall,) => |
|
OverloadedCallType::FnOverloadedCall, |
|
(&OverloadedCallType::FnMutOverloadedCall,) => |
|
OverloadedCallType::FnMutOverloadedCall, |
|
(&OverloadedCallType::FnOnceOverloadedCall,) => |
|
OverloadedCallType::FnOnceOverloadedCall, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for OverloadedCallType { } |
|
impl OverloadedCallType { |
|
fn from_trait_id(tcx: &ty::ctxt, trait_id: DefId) |
|
-> OverloadedCallType { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&[(tcx.lang_items.fn_once_trait(), |
|
FnOnceOverloadedCall), |
|
(tcx.lang_items.fn_mut_trait(), |
|
FnMutOverloadedCall), |
|
(tcx.lang_items.fn_trait(), |
|
FnOverloadedCall)]) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(&(maybe_function_trait, |
|
overloaded_call_type)) |
|
=> { |
|
match maybe_function_trait { |
|
Some(function_trait) if |
|
function_trait == trait_id => { |
|
return overloaded_call_type |
|
} |
|
_ => continue , |
|
} |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
tcx.sess.bug("overloaded call didn\'t map to known function trait") |
|
} |
|
fn from_method_id(tcx: &ty::ctxt, method_id: DefId) |
|
-> OverloadedCallType { |
|
let method = tcx.impl_or_trait_item(method_id); |
|
OverloadedCallType::from_trait_id(tcx, |
|
method.container().id()) |
|
} |
|
} |
|
pub struct ExprUseVisitor<'d, 't, 'a:'t, 'tcx:'a+'d> { |
|
typer: &'t infer::InferCtxt<'a, 'tcx>, |
|
mc: mc::MemCategorizationContext<'t, 'a, 'tcx>, |
|
delegate: &'d mut Delegate<'tcx>, |
|
} |
|
/// Whether the elements of an overloaded operation are passed by value or by reference |
|
enum PassArgs { ByValue, ByRef, } |
|
impl <'d, 't, 'a, 'tcx> ExprUseVisitor<'d, 't, 'a, 'tcx> { |
|
pub fn new(delegate: &'d mut (Delegate<'tcx>), |
|
typer: &'t infer::InferCtxt<'a, 'tcx>) |
|
-> ExprUseVisitor<'d, 't, 'a, 'tcx> where 'tcx:'a+'d { |
|
let mc: mc::MemCategorizationContext<'t, 'a, 'tcx> = |
|
mc::MemCategorizationContext::new(typer); |
|
ExprUseVisitor{typer: typer, mc: mc, delegate: delegate,} |
|
} |
|
pub fn walk_fn(&mut self, decl: &hir::FnDecl, body: &hir::Block) { |
|
self.walk_arg_patterns(decl, body); |
|
self.walk_block(body); |
|
} |
|
fn walk_arg_patterns(&mut self, decl: &hir::FnDecl, |
|
body: &hir::Block) { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&decl.inputs) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(arg) => { |
|
let arg_ty = |
|
match self.typer.node_ty(arg.pat.id) |
|
{ |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: |
|
::log::LogLocation |
|
= |
|
::log::LogLocation{line: |
|
299u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = |
|
::log::DEBUG; |
|
if { |
|
let lvl = |
|
lvl; |
|
(lvl != |
|
::log::DEBUG |
|
|| |
|
false) |
|
&& |
|
lvl <= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, |
|
&LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
let fn_body_scope = |
|
self.tcx().region_maps.node_extent(body.id); |
|
let arg_cmt = |
|
self.mc.cat_rvalue(arg.id, |
|
arg.pat.span, |
|
ty::ReScope(fn_body_scope), |
|
arg_ty); |
|
self.walk_irrefutable_pat(arg_cmt, |
|
&*arg.pat); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
fn tcx(&self) -> &'t ty::ctxt<'tcx> { self.typer.tcx } |
|
fn delegate_consume(&mut self, consume_id: ast::NodeId, |
|
consume_span: Span, cmt: mc::cmt<'tcx>) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 320u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["delegate_consume(consume_id=", |
|
", cmt=", |
|
")"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&consume_id, |
|
&cmt) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
let mode = copy_or_move(self.typer, &cmt, DirectRefMove); |
|
self.delegate.consume(consume_id, consume_span, cmt, mode); |
|
} |
|
fn consume_exprs(&mut self, exprs: &Vec<P<hir::Expr>>) { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(exprs) { |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(expr) => { |
|
self.consume_expr(&**expr); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
pub fn consume_expr(&mut self, expr: &hir::Expr) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 334u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["consume_expr(expr=", |
|
")"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&expr,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
let cmt = |
|
match self.mc.cat_expr(expr) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 336u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
self.delegate_consume(expr.id, expr.span, cmt); |
|
self.walk_expr(expr); |
|
} |
|
fn mutate_expr(&mut self, assignment_expr: &hir::Expr, |
|
expr: &hir::Expr, mode: MutateMode) { |
|
let cmt = |
|
match self.mc.cat_expr(expr) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 345u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
self.delegate.mutate(assignment_expr.id, assignment_expr.span, |
|
cmt, mode); |
|
self.walk_expr(expr); |
|
} |
|
fn borrow_expr(&mut self, expr: &hir::Expr, r: ty::Region, |
|
bk: ty::BorrowKind, cause: LoanCause) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 355u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["borrow_expr(expr=", |
|
", r=", |
|
", bk=", |
|
")"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&expr, |
|
&r, |
|
&bk) |
|
{ |
|
(__arg0, |
|
__arg1, |
|
__arg2) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg2, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
let cmt = |
|
match self.mc.cat_expr(expr) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 358u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause); |
|
self.walk_expr(expr) |
|
} |
|
fn select_from_expr(&mut self, expr: &hir::Expr) { |
|
self.walk_expr(expr) |
|
} |
|
pub fn walk_expr(&mut self, expr: &hir::Expr) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 369u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["walk_expr(expr=", |
|
")"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&expr,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
self.walk_adjustment(expr); |
|
match expr.node { |
|
hir::ExprPath(..) => { } |
|
hir::ExprUnary(hir::UnDeref, ref base) => { |
|
if !self.walk_overloaded_operator(expr, &**base, |
|
Vec::new(), |
|
PassArgs::ByRef) { |
|
self.select_from_expr(&**base); |
|
} |
|
} |
|
hir::ExprField(ref base, _) => { |
|
self.select_from_expr(&**base); |
|
} |
|
hir::ExprTupField(ref base, _) => { |
|
self.select_from_expr(&**base); |
|
} |
|
hir::ExprIndex(ref lhs, ref rhs) => { |
|
if !self.walk_overloaded_operator(expr, &**lhs, |
|
<[_]>::into_vec(::std::boxed::Box::new([&**rhs])), |
|
PassArgs::ByValue) { |
|
self.select_from_expr(&**lhs); |
|
self.consume_expr(&**rhs); |
|
} |
|
} |
|
hir::ExprRange(ref start, ref end) => { |
|
start.as_ref().map(|e| self.consume_expr(&**e)); |
|
end.as_ref().map(|e| self.consume_expr(&**e)); |
|
} |
|
hir::ExprCall(ref callee, ref args) => { |
|
self.walk_callee(expr, &**callee); |
|
self.consume_exprs(args); |
|
} |
|
hir::ExprMethodCall(_, _, ref args) => { |
|
self.consume_exprs(args); |
|
} |
|
hir::ExprStruct(_, ref fields, ref opt_with) => { |
|
self.walk_struct_expr(expr, fields, opt_with); |
|
} |
|
hir::ExprTup(ref exprs) => { self.consume_exprs(exprs); } |
|
hir::ExprIf(ref cond_expr, ref then_blk, |
|
ref opt_else_expr) => { |
|
self.consume_expr(&**cond_expr); |
|
self.walk_block(&**then_blk); |
|
match *opt_else_expr { |
|
Some(ref else_expr) => { |
|
self.consume_expr(&**else_expr); |
|
} |
|
_ => (), |
|
} |
|
} |
|
hir::ExprMatch(ref discr, ref arms, _) => { |
|
let discr_cmt = |
|
match self.mc.cat_expr(&**discr) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: |
|
431u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || |
|
false) && |
|
lvl <= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
self.borrow_expr(&**discr, ty::ReEmpty, ty::ImmBorrow, |
|
MatchDiscriminant); |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(arms) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(arm) |
|
=> { |
|
let mode = |
|
self.arm_move_mode(discr_cmt.clone(), |
|
arm); |
|
let mode = mode.match_mode(); |
|
self.walk_arm(discr_cmt.clone(), |
|
arm, mode); |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
hir::ExprVec(ref exprs) => { self.consume_exprs(exprs); } |
|
hir::ExprAddrOf(m, ref base) => { |
|
let expr_ty = |
|
match self.typer.node_ty(expr.id) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: |
|
449u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || |
|
false) && |
|
lvl <= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
match expr_ty.sty { |
|
ty::TyRef(&r, _) => { |
|
let bk = ty::BorrowKind::from_mutbl(m); |
|
self.borrow_expr(&**base, r, bk, AddrOf); |
|
} |
|
_ => (), |
|
} |
|
} |
|
hir::ExprInlineAsm(ref ia) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&ia.inputs) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(&(_, |
|
ref input)) |
|
=> { |
|
self.consume_expr(&**input); |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&ia.outputs) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(&(_, |
|
ref output, |
|
is_rw)) |
|
=> { |
|
self.mutate_expr(expr, |
|
&**output, |
|
if is_rw { |
|
WriteAndRead |
|
} else { |
|
JustWrite |
|
}); |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(..) |
|
=> { |
|
} |
|
hir::ExprLoop(ref blk, _) => { self.walk_block(&**blk); } |
|
hir::ExprWhile(ref cond_expr, ref blk, _) => { |
|
self.consume_expr(&**cond_expr); |
|
self.walk_block(&**blk); |
|
} |
|
hir::ExprUnary(op, ref lhs) => { |
|
let pass_args = |
|
if ::rustc_front::util::is_by_value_unop(op) { |
|
PassArgs::ByValue |
|
} else { PassArgs::ByRef }; |
|
if !self.walk_overloaded_operator(expr, &**lhs, |
|
Vec::new(), |
|
pass_args) { |
|
self.consume_expr(&**lhs); |
|
} |
|
} |
|
hir::ExprBinary(op, ref lhs, ref rhs) => { |
|
let pass_args = |
|
if ::rustc_front::util::is_by_value_binop(op.node) |
|
{ |
|
PassArgs::ByValue |
|
} else { PassArgs::ByRef }; |
|
if !self.walk_overloaded_operator(expr, &**lhs, |
|
<[_]>::into_vec(::std::boxed::Box::new([&**rhs])), |
|
pass_args) { |
|
self.consume_expr(&**lhs); |
|
self.consume_expr(&**rhs); |
|
} |
|
} |
|
hir::ExprBlock(ref blk) => { self.walk_block(&**blk); } |
|
hir::ExprRet(ref opt_expr) => { |
|
match *opt_expr { |
|
Some(ref expr) => { self.consume_expr(&**expr); } |
|
_ => (), |
|
} |
|
} |
|
hir::ExprAssign(ref lhs, ref rhs) => { |
|
self.mutate_expr(expr, &**lhs, JustWrite); |
|
self.consume_expr(&**rhs); |
|
} |
|
hir::ExprCast(ref base, _) => { |
|
self.consume_expr(&**base); |
|
} |
|
hir::ExprAssignOp(op, ref lhs, ref rhs) => { |
|
if !::rustc_front::util::is_by_value_binop(op.node) { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: ::rustc_front::util::is_by_value_binop(op.node)", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/middle/expr_use_visitor.rs", |
|
526u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
if !self.walk_overloaded_operator(expr, lhs, |
|
<[_]>::into_vec(::std::boxed::Box::new([rhs])), |
|
PassArgs::ByValue) { |
|
self.mutate_expr(expr, &**lhs, WriteAndRead); |
|
self.consume_expr(&**rhs); |
|
} |
|
} |
|
hir::ExprRepeat(ref base, ref count) => { |
|
self.consume_expr(&**base); |
|
self.consume_expr(&**count); |
|
} |
|
hir::ExprClosure(..) => { self.walk_captures(expr) } |
|
hir::ExprBox(ref base) => { self.consume_expr(&**base); } |
|
} |
|
} |
|
fn walk_callee(&mut self, call: &hir::Expr, callee: &hir::Expr) { |
|
let callee_ty = |
|
match self.typer.expr_ty_adjusted(callee) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 550u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 551u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["walk_callee: callee=", |
|
" callee_ty="]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&callee, |
|
&callee_ty) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
let call_scope = self.tcx().region_maps.node_extent(call.id); |
|
match callee_ty.sty { |
|
ty::TyBareFn(..) => { self.consume_expr(callee); } |
|
ty::TyError => { } |
|
_ => { |
|
let overloaded_call_type = |
|
match self.typer.node_method_id(ty::MethodCall::expr(call.id)) |
|
{ |
|
Some(method_id) => { |
|
OverloadedCallType::from_method_id(self.tcx(), |
|
method_id) |
|
} |
|
None => { |
|
self.tcx().sess.span_bug(callee.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["unexpected callee type "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&callee_ty,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}))) |
|
} |
|
}; |
|
match overloaded_call_type { |
|
FnMutOverloadedCall => { |
|
self.borrow_expr(callee, |
|
ty::ReScope(call_scope), |
|
ty::MutBorrow, |
|
ClosureInvocation); |
|
} |
|
FnOverloadedCall => { |
|
self.borrow_expr(callee, |
|
ty::ReScope(call_scope), |
|
ty::ImmBorrow, |
|
ClosureInvocation); |
|
} |
|
FnOnceOverloadedCall => self.consume_expr(callee), |
|
} |
|
} |
|
} |
|
} |
|
fn walk_stmt(&mut self, stmt: &hir::Stmt) { |
|
match stmt.node { |
|
hir::StmtDecl(ref decl, _) => { |
|
match decl.node { |
|
hir::DeclLocal(ref local) => { |
|
self.walk_local(&**local); |
|
} |
|
hir::DeclItem(_) => { } |
|
} |
|
} |
|
hir::StmtExpr(ref expr, _) | hir::StmtSemi(ref expr, _) => |
|
{ |
|
self.consume_expr(&**expr); |
|
} |
|
} |
|
} |
|
fn walk_local(&mut self, local: &hir::Local) { |
|
match local.init { |
|
None => { |
|
let delegate = &mut self.delegate; |
|
pat_util::pat_bindings(&self.typer.tcx.def_map, |
|
&*local.pat, |_, id, span, _| { |
|
delegate.decl_without_init(id, |
|
span); |
|
}) |
|
} |
|
Some(ref expr) => { |
|
self.walk_expr(&**expr); |
|
let init_cmt = |
|
match self.mc.cat_expr(&**expr) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: |
|
628u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || |
|
false) && |
|
lvl <= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
self.walk_irrefutable_pat(init_cmt, &*local.pat); |
|
} |
|
} |
|
} |
|
/// Indicates that the value of `blk` will be consumed, meaning either copied or moved |
|
/// depending on its type. |
|
fn walk_block(&mut self, blk: &hir::Block) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 637u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["walk_block(blk.id=", |
|
")"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&blk.id,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&blk.stmts) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(stmt) => { |
|
self.walk_stmt(&**stmt); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
match blk.expr { |
|
Some(ref tail_expr) => { |
|
self.consume_expr(&**tail_expr); |
|
} |
|
_ => (), |
|
} |
|
} |
|
fn walk_struct_expr(&mut self, _expr: &hir::Expr, |
|
fields: &Vec<hir::Field>, |
|
opt_with: &Option<P<hir::Expr>>) { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(fields) { |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(field) => { |
|
self.consume_expr(&*field.expr); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
let with_expr = |
|
match *opt_with { |
|
Some(ref w) => &**w, |
|
None => { return; } |
|
}; |
|
let with_cmt = |
|
match self.mc.cat_expr(&*with_expr) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 662u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
match with_cmt.ty.sty { |
|
ty::TyStruct(def, substs) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&def.struct_variant().fields) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(with_field) |
|
=> { |
|
if !contains_field_named(with_field, |
|
fields) |
|
{ |
|
let cmt_field = |
|
self.mc.cat_field(&*with_expr, |
|
with_cmt.clone(), |
|
with_field.name, |
|
with_field.ty(self.tcx(), |
|
substs)); |
|
self.delegate_consume(with_expr.id, |
|
with_expr.span, |
|
cmt_field); |
|
} |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
_ => { |
|
if !self.tcx().sess.has_errors() { |
|
self.tcx().sess.span_bug(with_expr.span, |
|
"with expression doesn\'t evaluate to a struct"); |
|
} |
|
} |
|
}; |
|
self.walk_expr(with_expr); |
|
fn contains_field_named(field: ty::FieldDef, |
|
fields: &Vec<hir::Field>) -> bool { |
|
fields.iter().any(|f| f.name.node == field.name) |
|
} |
|
} |
|
fn walk_adjustment(&mut self, expr: &hir::Expr) { |
|
let typer = self.typer; |
|
let adj = |
|
typer.adjustments().get(&expr.id).map(|x| x.clone()); |
|
match adj { |
|
Some(adjustment) => { |
|
match adjustment { |
|
adjustment::AdjustReifyFnPointer | |
|
adjustment::AdjustUnsafeFnPointer => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 717u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) |
|
&& |
|
lvl <= ::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
let cmt_unadjusted = |
|
match self.mc.cat_expr_unadjusted(expr) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: |
|
::log::LogLocation |
|
= |
|
::log::LogLocation{line: |
|
719u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != |
|
::log::DEBUG |
|
|| false) && |
|
lvl <= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
self.delegate_consume(expr.id, expr.span, |
|
cmt_unadjusted); |
|
} |
|
adjustment::AdjustDerefRef(ref adj) => { |
|
self.walk_autoderefref(expr, adj); |
|
} |
|
} |
|
} |
|
_ => (), |
|
} |
|
} |
|
/// Autoderefs for overloaded Deref calls in fact reference their receiver. That is, if we have |
|
/// `(*x)` where `x` is of type `Rc<T>`, then this in fact is equivalent to `x.deref()`. Since |
|
/// `deref()` is declared with `&self`, this is an autoref of `x`. |
|
fn walk_autoderefs(&mut self, expr: &hir::Expr, |
|
autoderefs: usize) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 735u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["walk_autoderefs expr=", |
|
" autoderefs="]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&expr, |
|
&autoderefs) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(0..autoderefs) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(i) => { |
|
let deref_id = |
|
ty::MethodCall::autoderef(expr.id, |
|
i as |
|
u32); |
|
match self.typer.node_method_ty(deref_id) |
|
{ |
|
None => { } |
|
Some(method_ty) => { |
|
let cmt = |
|
match self.mc.cat_expr_autoderefd(expr, |
|
i) |
|
{ |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: |
|
::log::LogLocation |
|
= |
|
::log::LogLocation{line: |
|
742u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = |
|
::log::DEBUG; |
|
if { |
|
let lvl = |
|
lvl; |
|
(lvl |
|
!= |
|
::log::DEBUG |
|
|| |
|
false) |
|
&& |
|
lvl |
|
<= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, |
|
&LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
let self_ty = |
|
method_ty.fn_sig().input(0); |
|
let self_ty = |
|
self.tcx().no_late_bound_regions(&self_ty).unwrap(); |
|
let (m, r) = |
|
match self_ty.sty { |
|
ty::TyRef(r, ref m) => |
|
(m.mutbl, r), |
|
_ => |
|
self.tcx().sess.span_bug(expr.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["bad overloaded deref type "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&method_ty,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt)], |
|
}))), |
|
}; |
|
let bk = |
|
ty::BorrowKind::from_mutbl(m); |
|
self.delegate.borrow(expr.id, |
|
expr.span, |
|
cmt, *r, |
|
bk, |
|
AutoRef); |
|
} |
|
} |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
fn walk_autoderefref(&mut self, expr: &hir::Expr, |
|
adj: &adjustment::AutoDerefRef<'tcx>) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 766u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["walk_autoderefref expr=", |
|
" adj="]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&expr, |
|
&adj) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
self.walk_autoderefs(expr, adj.autoderefs); |
|
let cmt_derefd = |
|
match self.mc.cat_expr_autoderefd(expr, adj.autoderefs) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 773u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
let cmt_refd = |
|
self.walk_autoref(expr, cmt_derefd, adj.autoref); |
|
if adj.unsize.is_some() { |
|
self.delegate_consume(expr.id, expr.span, cmt_refd); |
|
} |
|
} |
|
/// Walks the autoref `opt_autoref` applied to the autoderef'd |
|
/// `expr`. `cmt_derefd` is the mem-categorized form of `expr` |
|
/// after all relevant autoderefs have occurred. Because AutoRefs |
|
/// can be recursive, this function is recursive: it first walks |
|
/// deeply all the way down the autoref chain, and then processes |
|
/// the autorefs on the way out. At each point, it returns the |
|
/// `cmt` for the rvalue that will be produced by introduced an |
|
/// autoref. |
|
fn walk_autoref(&mut self, expr: &hir::Expr, |
|
cmt_base: mc::cmt<'tcx>, |
|
opt_autoref: Option<adjustment::AutoRef<'tcx>>) |
|
-> mc::cmt<'tcx> { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 799u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["walk_autoref(expr.id=", |
|
" cmt_derefd=", |
|
" opt_autoref=", |
|
")"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&expr.id, |
|
&cmt_base, |
|
&opt_autoref) |
|
{ |
|
(__arg0, |
|
__arg1, |
|
__arg2) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg2, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
let cmt_base_ty = cmt_base.ty; |
|
let autoref = |
|
match opt_autoref { |
|
Some(ref autoref) => autoref, |
|
None => { return cmt_base; } |
|
}; |
|
match *autoref { |
|
adjustment::AutoPtr(r, m) => { |
|
self.delegate.borrow(expr.id, expr.span, cmt_base, *r, |
|
ty::BorrowKind::from_mutbl(m), |
|
AutoRef); |
|
} |
|
adjustment::AutoUnsafe(m) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 825u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["walk_autoref: expr.id=", |
|
" cmt_base="]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&expr.id, |
|
&cmt_base) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
let r = |
|
ty::ReScope(self.tcx().region_maps.node_extent(expr.id)); |
|
self.delegate.borrow(expr.id, expr.span, cmt_base, r, |
|
ty::BorrowKind::from_mutbl(m), |
|
AutoUnsafe); |
|
} |
|
} |
|
let adj_ty = |
|
cmt_base_ty.adjust_for_autoref(self.tcx(), opt_autoref); |
|
self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty) |
|
} |
|
fn walk_overloaded_operator(&mut self, expr: &hir::Expr, |
|
receiver: &hir::Expr, |
|
rhs: Vec<&hir::Expr>, |
|
pass_args: PassArgs) -> bool { |
|
if !self.typer.is_method_call(expr.id) { return false; } |
|
match pass_args { |
|
PassArgs::ByValue => { |
|
self.consume_expr(receiver); |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&rhs) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(&arg) |
|
=> { |
|
self.consume_expr(arg); |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
return true; |
|
} |
|
PassArgs::ByRef => { } |
|
} |
|
self.walk_expr(receiver); |
|
let r = |
|
ty::ReScope(self.tcx().region_maps.node_extent(expr.id)); |
|
let bk = ty::ImmBorrow; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&rhs) { |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(&arg) => { |
|
self.borrow_expr(arg, r, bk, |
|
OverloadedOperator); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
return true; |
|
} |
|
fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, |
|
arm: &hir::Arm) -> TrackMatchMode { |
|
let mut mode = Unknown; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&arm.pats) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(pat) => { |
|
self.determine_pat_move_mode(discr_cmt.clone(), |
|
&**pat, |
|
&mut mode); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
mode |
|
} |
|
fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm, |
|
mode: MatchMode) { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&arm.pats) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(pat) => { |
|
self.walk_pat(discr_cmt.clone(), |
|
&**pat, mode); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
match arm.guard { |
|
Some(ref guard) => { self.consume_expr(&**guard); } |
|
_ => (), |
|
} |
|
self.consume_expr(&*arm.body); |
|
} |
|
/// Walks a pat that occurs in isolation (i.e. top-level of fn |
|
/// arg or let binding. *Not* a match arm or nested pat.) |
|
fn walk_irrefutable_pat(&mut self, cmt_discr: mc::cmt<'tcx>, |
|
pat: &hir::Pat) { |
|
let mut mode = Unknown; |
|
self.determine_pat_move_mode(cmt_discr.clone(), pat, |
|
&mut mode); |
|
let mode = mode.match_mode(); |
|
self.walk_pat(cmt_discr, pat, mode); |
|
} |
|
/// Identifies any bindings within `pat` and accumulates within |
|
/// `mode` whether the overall pattern/match structure is a move, |
|
/// copy, or borrow. |
|
fn determine_pat_move_mode(&mut self, cmt_discr: mc::cmt<'tcx>, |
|
pat: &hir::Pat, |
|
mode: &mut TrackMatchMode) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 932u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["determine_pat_move_mode cmt_discr=", |
|
" pat="]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&cmt_discr, |
|
&pat) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
match self.mc.cat_pattern(cmt_discr, pat, |
|
|_mc, cmt_pat, pat| { |
|
let tcx = self.tcx(); |
|
let def_map = &self.tcx().def_map; |
|
if pat_util::pat_is_binding(&def_map.borrow(), |
|
pat) { |
|
match pat.node { |
|
hir::PatIdent(hir::BindByRef(_), |
|
_, _) => |
|
mode.lub(BorrowingMatch), |
|
hir::PatIdent(hir::BindByValue(_), |
|
_, _) => { |
|
match copy_or_move(self.typer, |
|
&cmt_pat, |
|
PatBindingMove) |
|
{ |
|
Copy => |
|
mode.lub(CopyingMatch), |
|
Move(_) => |
|
mode.lub(MovingMatch), |
|
} |
|
} |
|
_ => { |
|
tcx.sess.span_bug(pat.span, |
|
"binding pattern not an identifier"); |
|
} |
|
} |
|
} }) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 934u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
} |
|
/// The core driver for walking a pattern; `match_mode` must be |
|
/// established up front, e.g. via `determine_pat_move_mode` (see |
|
/// also `walk_irrefutable_pat` for patterns that stand alone). |
|
fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, |
|
match_mode: MatchMode) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 964u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["walk_pat cmt_discr=", |
|
" pat="]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&cmt_discr, |
|
&pat) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
let mc = &self.mc; |
|
let typer = self.typer; |
|
let def_map = &self.tcx().def_map; |
|
let delegate = &mut self.delegate; |
|
match mc.cat_pattern(cmt_discr.clone(), pat, |
|
|mc, cmt_pat, pat| { |
|
if pat_util::pat_is_binding(&def_map.borrow(), |
|
pat) { |
|
let tcx = typer.tcx; |
|
if false { |
|
{ |
|
static LOC: |
|
::log::LogLocation = |
|
::log::LogLocation{line: |
|
971u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG |
|
|| false) && |
|
lvl <= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["binding cmt_pat=", |
|
" pat=", |
|
" match_mode="]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&cmt_pat, |
|
&pat, |
|
&match_mode) |
|
{ |
|
(__arg0, |
|
__arg1, |
|
__arg2) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg2, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
let pat_ty = |
|
match typer.node_ty(pat.id) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: |
|
::log::LogLocation |
|
= |
|
::log::LogLocation{line: |
|
971u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = |
|
::log::DEBUG; |
|
if { |
|
let lvl = |
|
lvl; |
|
(lvl != |
|
::log::DEBUG |
|
|| |
|
false) |
|
&& |
|
lvl <= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, |
|
&LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
let def = |
|
def_map.borrow().get(&pat.id).unwrap().full_def(); |
|
match mc.cat_def(pat.id, pat.span, |
|
pat_ty, def) { |
|
Ok(binding_cmt) => { |
|
delegate.mutate(pat.id, |
|
pat.span, |
|
binding_cmt, |
|
Init); |
|
} |
|
Err(_) => { } |
|
} |
|
match pat.node { |
|
hir::PatIdent(hir::BindByRef(m), |
|
_, _) => { |
|
match pat_ty.sty { |
|
ty::TyRef(&r, _) => { |
|
let bk = |
|
ty::BorrowKind::from_mutbl(m); |
|
delegate.borrow(pat.id, |
|
pat.span, |
|
cmt_pat, |
|
r, |
|
bk, |
|
RefBinding); |
|
} |
|
_ => (), |
|
} |
|
} |
|
hir::PatIdent(hir::BindByValue(_), |
|
_, _) => { |
|
let mode = |
|
copy_or_move(typer, |
|
&cmt_pat, |
|
PatBindingMove); |
|
if false { |
|
{ |
|
static LOC: |
|
::log::LogLocation |
|
= |
|
::log::LogLocation{line: |
|
971u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = |
|
::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != |
|
::log::DEBUG |
|
|| false) |
|
&& |
|
lvl <= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, |
|
&LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["walk_pat binding consuming pat"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
delegate.consume_pat(pat, |
|
cmt_pat, |
|
mode); |
|
} |
|
_ => { |
|
tcx.sess.span_bug(pat.span, |
|
"binding pattern not an identifier"); |
|
} |
|
} |
|
} else { |
|
match pat.node { |
|
hir::PatVec(_, |
|
Some(ref slice_pat), |
|
_) => { |
|
let (slice_cmt, slice_mutbl, |
|
slice_r) = |
|
match mc.cat_slice_pattern(cmt_pat, |
|
&**slice_pat) |
|
{ |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: |
|
::log::LogLocation |
|
= |
|
::log::LogLocation{line: |
|
971u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = |
|
::log::DEBUG; |
|
if { |
|
let lvl = |
|
lvl; |
|
(lvl |
|
!= |
|
::log::DEBUG |
|
|| |
|
false) |
|
&& |
|
lvl |
|
<= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, |
|
&LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
let slice_bk = |
|
ty::BorrowKind::from_mutbl(slice_mutbl); |
|
delegate.borrow(pat.id, |
|
pat.span, |
|
slice_cmt, |
|
slice_r, |
|
slice_bk, |
|
RefBinding); |
|
} |
|
_ => { } |
|
} |
|
} }) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 971u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
match mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| { |
|
let def_map = def_map.borrow(); |
|
let tcx = typer.tcx; |
|
match pat.node { |
|
hir::PatEnum(_, _) | |
|
hir::PatQPath(..) | |
|
hir::PatIdent(_, _, None) | |
|
hir::PatStruct(..) => { |
|
match def_map.get(&pat.id).map(|d| |
|
d.full_def()) |
|
{ |
|
None => { } |
|
Some(def::DefVariant(enum_did, |
|
variant_did, |
|
_is_struct)) |
|
=> { |
|
let downcast_cmt = |
|
if tcx.lookup_adt_def(enum_did).is_univariant() |
|
{ |
|
cmt_pat |
|
} else { |
|
let cmt_pat_ty = |
|
cmt_pat.ty; |
|
mc.cat_downcast(pat, |
|
cmt_pat, |
|
cmt_pat_ty, |
|
variant_did) |
|
}; |
|
if false { |
|
{ |
|
static LOC: |
|
::log::LogLocation |
|
= |
|
::log::LogLocation{line: |
|
1058u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = |
|
::log::DEBUG; |
|
if { |
|
let lvl = |
|
lvl; |
|
(lvl != |
|
::log::DEBUG |
|
|| |
|
false) |
|
&& |
|
lvl <= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, |
|
&LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["variant downcast_cmt=", |
|
" pat="]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&downcast_cmt, |
|
&pat) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
delegate.matched_pat(pat, |
|
downcast_cmt, |
|
match_mode); |
|
} |
|
Some(def::DefStruct(..)) | |
|
Some(def::DefTy(_, false)) => |
|
{ |
|
if false { |
|
{ |
|
static LOC: |
|
::log::LogLocation |
|
= |
|
::log::LogLocation{line: |
|
1058u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = |
|
::log::DEBUG; |
|
if { |
|
let lvl = |
|
lvl; |
|
(lvl != |
|
::log::DEBUG |
|
|| |
|
false) |
|
&& |
|
lvl <= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, |
|
&LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["struct cmt_pat=", |
|
" pat="]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&cmt_pat, |
|
&pat) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
delegate.matched_pat(pat, |
|
cmt_pat, |
|
match_mode); |
|
} |
|
Some(def::DefConst(..)) | |
|
Some(def::DefAssociatedConst(..)) |
|
| Some(def::DefLocal(..)) => |
|
{ |
|
} |
|
Some(def@def::DefTy(_, true)) |
|
=> { |
|
if !tcx.sess.has_errors() |
|
{ |
|
let msg = |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["Pattern has unexpected type: ", |
|
" and type "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&def, |
|
&cmt_pat.ty) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})); |
|
tcx.sess.span_bug(pat.span, |
|
&msg) |
|
} |
|
} |
|
Some(def) => { |
|
if !tcx.sess.has_errors() |
|
{ |
|
let msg = |
|
::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["Pattern has unexpected def: ", |
|
" and type "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&def, |
|
&cmt_pat.ty) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})); |
|
tcx.sess.span_bug(pat.span, |
|
&msg[..]) |
|
} |
|
} |
|
} |
|
} |
|
hir::PatIdent(_, _, Some(_)) => { } |
|
hir::PatWild | hir::PatTup(..) | |
|
hir::PatBox(..) | hir::PatRegion(..) |
|
| hir::PatLit(..) | hir::PatRange(..) |
|
| hir::PatVec(..) => { |
|
} |
|
} }) { |
|
Ok(v) => v, |
|
Err(()) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 1058u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
} |
|
fn walk_captures(&mut self, closure_expr: &hir::Expr) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 1157u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["walk_captures(", |
|
")"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&closure_expr,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
self.tcx().with_freevars(closure_expr.id, |freevars| { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(freevars) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(freevar) |
|
=> { |
|
let id_var = |
|
freevar.def.var_id(); |
|
let upvar_id = |
|
ty::UpvarId{var_id: |
|
id_var, |
|
closure_expr_id: |
|
closure_expr.id,}; |
|
let upvar_capture = |
|
self.typer.upvar_capture(upvar_id).unwrap(); |
|
let cmt_var = |
|
match self.cat_captured_var(closure_expr.id, |
|
closure_expr.span, |
|
freevar.def) |
|
{ |
|
Ok(v) |
|
=> v, |
|
Err(()) |
|
=> { |
|
if false |
|
{ |
|
{ |
|
static LOC: |
|
::log::LogLocation |
|
= |
|
::log::LogLocation{line: |
|
1165u32, |
|
file: |
|
"src/librustc/middle/expr_use_visitor.rs", |
|
module_path: |
|
"rustc::middle::expr_use_visitor",}; |
|
let lvl = |
|
::log::DEBUG; |
|
if { |
|
let lvl = |
|
lvl; |
|
(lvl |
|
!= |
|
::log::DEBUG |
|
|| |
|
false) |
|
&& |
|
lvl |
|
<= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::expr_use_visitor") |
|
} |
|
{ |
|
::log::log(lvl, |
|
&LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mc reported err"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
} |
|
} |
|
}; |
|
return |
|
} |
|
}; |
|
match upvar_capture |
|
{ |
|
ty::UpvarCapture::ByValue |
|
=> { |
|
let mode = |
|
copy_or_move(self.typer, |
|
&cmt_var, |
|
CaptureMove); |
|
self.delegate.consume(closure_expr.id, |
|
freevar.span, |
|
cmt_var, |
|
mode); |
|
} |
|
ty::UpvarCapture::ByRef(upvar_borrow) |
|
=> { |
|
self.delegate.borrow(closure_expr.id, |
|
closure_expr.span, |
|
cmt_var, |
|
upvar_borrow.region, |
|
upvar_borrow.kind, |
|
ClosureCapture(freevar.span)); |
|
} |
|
} |
|
} |
|
::std::option::Option::None |
|
=> break , |
|
} |
|
}, |
|
}; |
|
result |
|
} }); |
|
} |
|
fn cat_captured_var(&mut self, closure_id: ast::NodeId, |
|
closure_span: Span, upvar_def: def::Def) |
|
-> mc::McResult<mc::cmt<'tcx>> { |
|
let var_id = upvar_def.var_id(); |
|
let var_ty = |
|
match self.typer.node_ty(var_id) { |
|
::std::result::Result::Ok(val) => val, |
|
::std::result::Result::Err(err) => { |
|
return ::std::result::Result::Err(::std::convert::From::from(err)) |
|
} |
|
}; |
|
self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def) |
|
} |
|
} |
|
fn copy_or_move<'a, |
|
'tcx>(typer: &infer::InferCtxt<'a, 'tcx>, |
|
cmt: &mc::cmt<'tcx>, move_reason: MoveReason) |
|
-> ConsumeMode { |
|
if typer.type_moves_by_default(cmt.ty, cmt.span) { |
|
Move(move_reason) |
|
} else { Copy } |
|
} |
|
} |
|
pub mod cfg { |
|
//! Module that constructs a control-flow graph representing an item. |
|
//! Uses `Graph` as the underlying representation. |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
use rustc_data_structures::graph; |
|
use middle::ty; |
|
use syntax::ast; |
|
use rustc_front::hir; |
|
mod construct { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
use rustc_data_structures::graph; |
|
use middle::cfg::*; |
|
use middle::def; |
|
use middle::pat_util; |
|
use middle::ty; |
|
use syntax::ast; |
|
use syntax::ptr::P; |
|
use rustc_front::hir; |
|
struct CFGBuilder<'a, 'tcx:'a> { |
|
tcx: &'a ty::ctxt<'tcx>, |
|
graph: CFGGraph, |
|
fn_exit: CFGIndex, |
|
loop_scopes: Vec<LoopScope>, |
|
} |
|
struct LoopScope { |
|
loop_id: ast::NodeId, |
|
continue_index: CFGIndex, |
|
break_index: CFGIndex, |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for LoopScope { |
|
#[inline] |
|
fn clone(&self) -> LoopScope { |
|
match *self { |
|
LoopScope { |
|
loop_id: ref __self_0_0, |
|
continue_index: ref __self_0_1, |
|
break_index: ref __self_0_2 } => |
|
LoopScope{loop_id: |
|
::std::clone::Clone::clone(&(*__self_0_0)), |
|
continue_index: |
|
::std::clone::Clone::clone(&(*__self_0_1)), |
|
break_index: |
|
::std::clone::Clone::clone(&(*__self_0_2)),}, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for LoopScope { } |
|
pub fn construct(tcx: &ty::ctxt, blk: &hir::Block) -> CFG { |
|
let mut graph = graph::Graph::new(); |
|
let entry = graph.add_node(CFGNodeData::Entry); |
|
let fn_exit = graph.add_node(CFGNodeData::Exit); |
|
let block_exit; |
|
let mut cfg_builder = |
|
CFGBuilder{graph: graph, |
|
fn_exit: fn_exit, |
|
tcx: tcx, |
|
loop_scopes: Vec::new(),}; |
|
block_exit = cfg_builder.block(blk, entry); |
|
cfg_builder.add_contained_edge(block_exit, fn_exit); |
|
let CFGBuilder { graph, .. } = cfg_builder; |
|
CFG{graph: graph, entry: entry, exit: fn_exit,} |
|
} |
|
impl <'a, 'tcx> CFGBuilder<'a, 'tcx> { |
|
fn block(&mut self, blk: &hir::Block, pred: CFGIndex) |
|
-> CFGIndex { |
|
let mut stmts_exit = pred; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&blk.stmts) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(stmt) => { |
|
stmts_exit = |
|
self.stmt(&**stmt, |
|
stmts_exit); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
let expr_exit = self.opt_expr(&blk.expr, stmts_exit); |
|
self.add_ast_node(blk.id, &[expr_exit]) |
|
} |
|
fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) |
|
-> CFGIndex { |
|
match stmt.node { |
|
hir::StmtDecl(ref decl, id) => { |
|
let exit = self.decl(&**decl, pred); |
|
self.add_ast_node(id, &[exit]) |
|
} |
|
hir::StmtExpr(ref expr, id) | |
|
hir::StmtSemi(ref expr, id) => { |
|
let exit = self.expr(&**expr, pred); |
|
self.add_ast_node(id, &[exit]) |
|
} |
|
} |
|
} |
|
fn decl(&mut self, decl: &hir::Decl, pred: CFGIndex) |
|
-> CFGIndex { |
|
match decl.node { |
|
hir::DeclLocal(ref local) => { |
|
let init_exit = self.opt_expr(&local.init, pred); |
|
self.pat(&*local.pat, init_exit) |
|
} |
|
hir::DeclItem(_) => { pred } |
|
} |
|
} |
|
fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) |
|
-> CFGIndex { |
|
match pat.node { |
|
hir::PatIdent(_, _, None) | hir::PatEnum(_, None) | |
|
hir::PatQPath(..) | hir::PatLit(..) | |
|
hir::PatRange(..) | hir::PatWild => { |
|
self.add_ast_node(pat.id, &[pred]) |
|
} |
|
hir::PatBox(ref subpat) | |
|
hir::PatRegion(ref subpat, _) | |
|
hir::PatIdent(_, _, Some(ref subpat)) => { |
|
let subpat_exit = self.pat(&**subpat, pred); |
|
self.add_ast_node(pat.id, &[subpat_exit]) |
|
} |
|
hir::PatEnum(_, Some(ref subpats)) | |
|
hir::PatTup(ref subpats) => { |
|
let pats_exit = |
|
self.pats_all(subpats.iter(), pred); |
|
self.add_ast_node(pat.id, &[pats_exit]) |
|
} |
|
hir::PatStruct(_, ref subpats, _) => { |
|
let pats_exit = |
|
self.pats_all(subpats.iter().map(|f| |
|
&f.node.pat), |
|
pred); |
|
self.add_ast_node(pat.id, &[pats_exit]) |
|
} |
|
hir::PatVec(ref pre, ref vec, ref post) => { |
|
let pre_exit = self.pats_all(pre.iter(), pred); |
|
let vec_exit = |
|
self.pats_all(vec.iter(), pre_exit); |
|
let post_exit = |
|
self.pats_all(post.iter(), vec_exit); |
|
self.add_ast_node(pat.id, &[post_exit]) |
|
} |
|
} |
|
} |
|
fn pats_all<'b, I: Iterator<Item = |
|
&'b P<hir::Pat>>>(&mut self, pats: I, |
|
pred: CFGIndex) -> CFGIndex { |
|
//! Handles case where all of the patterns must match. |
|
pats.fold(pred, |pred, pat| self.pat(&**pat, pred)) |
|
} |
|
fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) |
|
-> CFGIndex { |
|
match expr.node { |
|
hir::ExprBlock(ref blk) => { |
|
let blk_exit = self.block(&**blk, pred); |
|
self.add_ast_node(expr.id, &[blk_exit]) |
|
} |
|
hir::ExprIf(ref cond, ref then, None) => { |
|
let cond_exit = self.expr(&**cond, pred); |
|
let then_exit = self.block(&**then, cond_exit); |
|
self.add_ast_node(expr.id, |
|
&[cond_exit, then_exit]) |
|
} |
|
hir::ExprIf(ref cond, ref then, Some(ref otherwise)) |
|
=> { |
|
let cond_exit = self.expr(&**cond, pred); |
|
let then_exit = self.block(&**then, cond_exit); |
|
let else_exit = |
|
self.expr(&**otherwise, cond_exit); |
|
self.add_ast_node(expr.id, |
|
&[then_exit, else_exit]) |
|
} |
|
hir::ExprWhile(ref cond, ref body, _) => { |
|
let loopback = self.add_dummy_node(&[pred]); |
|
let cond_exit = self.expr(&**cond, loopback); |
|
let expr_exit = |
|
self.add_ast_node(expr.id, &[cond_exit]); |
|
self.loop_scopes.push(LoopScope{loop_id: expr.id, |
|
continue_index: |
|
loopback, |
|
break_index: |
|
expr_exit,}); |
|
let body_exit = self.block(&**body, cond_exit); |
|
self.add_contained_edge(body_exit, loopback); |
|
self.loop_scopes.pop(); |
|
expr_exit |
|
} |
|
hir::ExprLoop(ref body, _) => { |
|
let loopback = self.add_dummy_node(&[pred]); |
|
let expr_exit = self.add_ast_node(expr.id, &[]); |
|
self.loop_scopes.push(LoopScope{loop_id: expr.id, |
|
continue_index: |
|
loopback, |
|
break_index: |
|
expr_exit,}); |
|
let body_exit = self.block(&**body, loopback); |
|
self.add_contained_edge(body_exit, loopback); |
|
self.loop_scopes.pop(); |
|
expr_exit |
|
} |
|
hir::ExprMatch(ref discr, ref arms, _) => { |
|
self.match_(expr.id, &discr, &arms, pred) |
|
} |
|
hir::ExprBinary(op, ref l, ref r) if |
|
::rustc_front::util::lazy_binop(op.node) => { |
|
let l_exit = self.expr(&**l, pred); |
|
let r_exit = self.expr(&**r, l_exit); |
|
self.add_ast_node(expr.id, &[l_exit, r_exit]) |
|
} |
|
hir::ExprRet(ref v) => { |
|
let v_exit = self.opt_expr(v, pred); |
|
let b = self.add_ast_node(expr.id, &[v_exit]); |
|
self.add_returning_edge(expr, b); |
|
self.add_unreachable_node() |
|
} |
|
hir::ExprBreak(label) => { |
|
let loop_scope = |
|
self.find_scope(expr, |
|
label.map(|l| l.node.name)); |
|
let b = self.add_ast_node(expr.id, &[pred]); |
|
self.add_exiting_edge(expr, b, loop_scope, |
|
loop_scope.break_index); |
|
self.add_unreachable_node() |
|
} |
|
hir::ExprAgain(label) => { |
|
let loop_scope = |
|
self.find_scope(expr, |
|
label.map(|l| l.node.name)); |
|
let a = self.add_ast_node(expr.id, &[pred]); |
|
self.add_exiting_edge(expr, a, loop_scope, |
|
loop_scope.continue_index); |
|
self.add_unreachable_node() |
|
} |
|
hir::ExprVec(ref elems) => { |
|
self.straightline(expr, pred, |
|
elems.iter().map(|e| &**e)) |
|
} |
|
hir::ExprCall(ref func, ref args) => { |
|
self.call(expr, pred, &**func, |
|
args.iter().map(|e| &**e)) |
|
} |
|
hir::ExprMethodCall(_, _, ref args) => { |
|
self.call(expr, pred, &*args[0], |
|
args[1..].iter().map(|e| &**e)) |
|
} |
|
hir::ExprIndex(ref l, ref r) | |
|
hir::ExprBinary(_, ref l, ref r) if |
|
self.tcx.is_method_call(expr.id) => { |
|
self.call(expr, pred, &**l, |
|
Some(&**r).into_iter()) |
|
} |
|
hir::ExprRange(ref start, ref end) => { |
|
let fields = |
|
start.as_ref().map(|e| |
|
&**e).into_iter().chain(end.as_ref().map(|e| |
|
&**e)); |
|
self.straightline(expr, pred, fields) |
|
} |
|
hir::ExprUnary(_, ref e) if |
|
self.tcx.is_method_call(expr.id) => { |
|
self.call(expr, pred, &**e, |
|
None::<hir::Expr>.iter()) |
|
} |
|
hir::ExprTup(ref exprs) => { |
|
self.straightline(expr, pred, |
|
exprs.iter().map(|e| &**e)) |
|
} |
|
hir::ExprStruct(_, ref fields, ref base) => { |
|
let field_cfg = |
|
self.straightline(expr, pred, |
|
fields.iter().map(|f| |
|
&*f.expr)); |
|
self.opt_expr(base, field_cfg) |
|
} |
|
hir::ExprRepeat(ref elem, ref count) => { |
|
self.straightline(expr, pred, |
|
[elem, |
|
count].iter().map(|&e| &**e)) |
|
} |
|
hir::ExprAssign(ref l, ref r) | |
|
hir::ExprAssignOp(_, ref l, ref r) => { |
|
self.straightline(expr, pred, |
|
[r, l].iter().map(|&e| &**e)) |
|
} |
|
hir::ExprIndex(ref l, ref r) | |
|
hir::ExprBinary(_, ref l, ref r) => { |
|
self.straightline(expr, pred, |
|
[l, r].iter().map(|&e| &**e)) |
|
} |
|
hir::ExprBox(ref e) | hir::ExprAddrOf(_, ref e) | |
|
hir::ExprCast(ref e, _) | hir::ExprUnary(_, ref e) | |
|
hir::ExprField(ref e, _) | hir::ExprTupField(ref e, _) |
|
=> { |
|
self.straightline(expr, pred, |
|
Some(&**e).into_iter()) |
|
} |
|
hir::ExprInlineAsm(ref inline_asm) => { |
|
let inputs = inline_asm.inputs.iter(); |
|
let outputs = inline_asm.outputs.iter(); |
|
let post_inputs = |
|
self.exprs(inputs.map(|a| { |
|
if false { |
|
{ |
|
static LOC: |
|
::log::LogLocation |
|
= |
|
::log::LogLocation{line: |
|
365u32, |
|
file: |
|
"src/librustc/middle/cfg/construct.rs", |
|
module_path: |
|
"rustc::middle::cfg::construct",}; |
|
let lvl = |
|
::log::DEBUG; |
|
if { |
|
let lvl = |
|
lvl; |
|
(lvl != |
|
::log::DEBUG |
|
|| |
|
false) |
|
&& |
|
lvl |
|
<= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::cfg::construct") |
|
} { |
|
::log::log(lvl, |
|
&LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["cfg::construct InlineAsm id:", |
|
" input:"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&expr.id, |
|
&a) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
let &(_, ref expr) = a; |
|
&**expr }), pred); |
|
let post_outputs = |
|
self.exprs(outputs.map(|a| { |
|
if false { |
|
{ |
|
static LOC: |
|
::log::LogLocation |
|
= |
|
::log::LogLocation{line: |
|
370u32, |
|
file: |
|
"src/librustc/middle/cfg/construct.rs", |
|
module_path: |
|
"rustc::middle::cfg::construct",}; |
|
let lvl = |
|
::log::DEBUG; |
|
if { |
|
let lvl = |
|
lvl; |
|
(lvl != |
|
::log::DEBUG |
|
|| |
|
false) |
|
&& |
|
lvl |
|
<= |
|
::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::cfg::construct") |
|
} { |
|
::log::log(lvl, |
|
&LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["cfg::construct InlineAsm id:", |
|
" output:"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&expr.id, |
|
&a) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
let &(_, ref expr, _) = |
|
a; &**expr }), |
|
post_inputs); |
|
self.add_ast_node(expr.id, &[post_outputs]) |
|
} |
|
hir::ExprClosure(..) | hir::ExprLit(..) | |
|
hir::ExprPath(..) => { |
|
self.straightline(expr, pred, |
|
None::<hir::Expr>.iter()) |
|
} |
|
} |
|
} |
|
fn call<'b, I: Iterator<Item = |
|
&'b hir::Expr>>(&mut self, call_expr: &hir::Expr, |
|
pred: CFGIndex, |
|
func_or_rcvr: &hir::Expr, args: I) |
|
-> CFGIndex { |
|
let method_call = ty::MethodCall::expr(call_expr.id); |
|
let fn_ty = |
|
match self.tcx.tables.borrow().method_map.get(&method_call) |
|
{ |
|
Some(method) => method.ty, |
|
None => self.tcx.expr_ty_adjusted(func_or_rcvr), |
|
}; |
|
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred); |
|
let ret = |
|
self.straightline(call_expr, func_or_rcvr_exit, args); |
|
if fn_ty.fn_ret().diverges() { |
|
self.add_unreachable_node() |
|
} else { ret } |
|
} |
|
fn exprs<'b, I: Iterator<Item = |
|
&'b hir::Expr>>(&mut self, exprs: I, pred: CFGIndex) |
|
-> CFGIndex { |
|
//! Constructs graph for `exprs` evaluated in order |
|
exprs.fold(pred, |p, e| self.expr(e, p)) |
|
} |
|
fn opt_expr(&mut self, opt_expr: &Option<P<hir::Expr>>, |
|
pred: CFGIndex) -> CFGIndex { |
|
//! Constructs graph for `opt_expr` evaluated, if Some |
|
opt_expr.iter().fold(pred, |p, e| self.expr(&**e, p)) |
|
} |
|
fn straightline<'b, I: Iterator<Item = |
|
&'b hir::Expr>>(&mut self, expr: &hir::Expr, |
|
pred: CFGIndex, subexprs: I) |
|
-> CFGIndex { |
|
//! Handles case of an expression that evaluates `subexprs` in order |
|
let subexprs_exit = self.exprs(subexprs, pred); |
|
self.add_ast_node(expr.id, &[subexprs_exit]) |
|
} |
|
fn match_(&mut self, id: ast::NodeId, discr: &hir::Expr, |
|
arms: &[hir::Arm], pred: CFGIndex) -> CFGIndex { |
|
let discr_exit = self.expr(discr, pred); |
|
let expr_exit = self.add_ast_node(id, &[]); |
|
let mut prev_guards = Vec::new(); |
|
let mut prev_has_bindings = false; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(arms) { |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(arm) => { |
|
let arm_exit = |
|
self.add_dummy_node(&[]); |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&arm.pats) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(pat) |
|
=> { |
|
let mut pat_exit = |
|
self.pat(&**pat, |
|
discr_exit); |
|
match arm.guard |
|
{ |
|
Some(ref guard) |
|
=> { |
|
let guard_start = |
|
self.add_dummy_node(&[pat_exit]); |
|
let guard_exit = |
|
self.expr(&**guard, |
|
guard_start); |
|
let this_has_bindings = |
|
pat_util::pat_contains_bindings_or_wild(&self.tcx.def_map.borrow(), |
|
&**pat); |
|
if prev_has_bindings |
|
|| |
|
this_has_bindings |
|
{ |
|
loop |
|
{ |
|
match prev_guards.pop() |
|
{ |
|
Some(prev) |
|
=> |
|
{ |
|
self.add_contained_edge(prev, |
|
guard_start); |
|
} |
|
_ |
|
=> |
|
break |
|
, |
|
} |
|
} |
|
} |
|
prev_has_bindings |
|
= |
|
this_has_bindings; |
|
prev_guards.push(guard_exit); |
|
pat_exit |
|
= |
|
guard_exit; |
|
} |
|
_ => |
|
(), |
|
} |
|
self.add_contained_edge(pat_exit, |
|
arm_exit); |
|
} |
|
::std::option::Option::None |
|
=> break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
let body_exit = |
|
self.expr(&arm.body, |
|
arm_exit); |
|
self.add_contained_edge(body_exit, |
|
expr_exit); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
expr_exit |
|
} |
|
fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex { |
|
self.add_node(CFGNodeData::Dummy, preds) |
|
} |
|
fn add_ast_node(&mut self, id: ast::NodeId, |
|
preds: &[CFGIndex]) -> CFGIndex { |
|
if !(id != ast::DUMMY_NODE_ID) { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: id != ast::DUMMY_NODE_ID", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/middle/cfg/construct.rs", |
|
536u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
self.add_node(CFGNodeData::AST(id), preds) |
|
} |
|
fn add_unreachable_node(&mut self) -> CFGIndex { |
|
self.add_node(CFGNodeData::Unreachable, &[]) |
|
} |
|
fn add_node(&mut self, data: CFGNodeData, preds: &[CFGIndex]) |
|
-> CFGIndex { |
|
let node = self.graph.add_node(data); |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(preds) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(&pred) => |
|
{ |
|
self.add_contained_edge(pred, |
|
node); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
node |
|
} |
|
fn add_contained_edge(&mut self, source: CFGIndex, |
|
target: CFGIndex) { |
|
let data = |
|
CFGEdgeData{exiting_scopes: |
|
<[_]>::into_vec(::std::boxed::Box::new([])),}; |
|
self.graph.add_edge(source, target, data); |
|
} |
|
fn add_exiting_edge(&mut self, from_expr: &hir::Expr, |
|
from_index: CFGIndex, to_loop: LoopScope, |
|
to_index: CFGIndex) { |
|
let mut data = |
|
CFGEdgeData{exiting_scopes: |
|
<[_]>::into_vec(::std::boxed::Box::new([])),}; |
|
let mut scope = |
|
self.tcx.region_maps.node_extent(from_expr.id); |
|
let target_scope = |
|
self.tcx.region_maps.node_extent(to_loop.loop_id); |
|
while scope != target_scope { |
|
data.exiting_scopes.push(scope.node_id(&self.tcx.region_maps)); |
|
scope = self.tcx.region_maps.encl_scope(scope); |
|
} |
|
self.graph.add_edge(from_index, to_index, data); |
|
} |
|
fn add_returning_edge(&mut self, _from_expr: &hir::Expr, |
|
from_index: CFGIndex) { |
|
let mut data = |
|
CFGEdgeData{exiting_scopes: |
|
<[_]>::into_vec(::std::boxed::Box::new([])),}; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(self.loop_scopes.iter().rev()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(&LoopScope { |
|
loop_id: id, |
|
.. }) => { |
|
data.exiting_scopes.push(id); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
self.graph.add_edge(from_index, self.fn_exit, data); |
|
} |
|
fn find_scope(&self, expr: &hir::Expr, |
|
label: Option<ast::Name>) -> LoopScope { |
|
if label.is_none() { |
|
return *self.loop_scopes.last().unwrap(); |
|
} |
|
match self.tcx.def_map.borrow().get(&expr.id).map(|d| |
|
d.full_def()) |
|
{ |
|
Some(def::DefLabel(loop_id)) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&self.loop_scopes) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(l) |
|
=> { |
|
if l.loop_id == loop_id { |
|
return *l; |
|
} |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
self.tcx.sess.span_bug(expr.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["no loop scope for id "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&loop_id,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}))); |
|
} |
|
r => { |
|
self.tcx.sess.span_bug(expr.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["bad entry `", |
|
"` in def_map for label"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&r,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt)], |
|
}))); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
pub mod graphviz { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
/// This module provides linkage between rustc::middle::graph and |
|
/// libgraphviz traits. |
|
use std::borrow::IntoCow; |
|
use graphviz as dot; |
|
use syntax::ast; |
|
use front::map as ast_map; |
|
use middle::cfg; |
|
pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode); |
|
pub type Edge<'a> = &'a cfg::CFGEdge; |
|
pub struct LabelledCFG<'a, 'ast:'a> { |
|
pub ast_map: &'a ast_map::Map<'ast>, |
|
pub cfg: &'a cfg::CFG, |
|
pub name: String, |
|
/// `labelled_edges` controls whether we emit labels on the edges |
|
pub labelled_edges: bool, |
|
} |
|
fn replace_newline_with_backslash_l(s: String) -> String { |
|
if s.contains("\n") { |
|
let mut s = s.replace("\n", "\\l"); |
|
let mut last_two: Vec<_> = |
|
s.chars().rev().take(2).collect(); |
|
last_two.reverse(); |
|
if last_two != ['\\', 'l'] { s.push_str("\\l"); } |
|
s |
|
} else { s } |
|
} |
|
impl <'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for |
|
LabelledCFG<'a, 'ast> { |
|
fn graph_id(&'a self) -> dot::Id<'a> { |
|
dot::Id::new(&self.name[..]).unwrap() |
|
} |
|
fn node_id(&'a self, &(i, _): &Node<'a>) -> dot::Id<'a> { |
|
dot::Id::new(::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["N"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&i.node_id(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}))).unwrap() |
|
} |
|
fn node_label(&'a self, &(i, n): &Node<'a>) |
|
-> dot::LabelText<'a> { |
|
if i == self.cfg.entry { |
|
dot::LabelText::LabelStr("entry".into_cow()) |
|
} else if i == self.cfg.exit { |
|
dot::LabelText::LabelStr("exit".into_cow()) |
|
} else if n.data.id() == ast::DUMMY_NODE_ID { |
|
dot::LabelText::LabelStr("(dummy_node)".into_cow()) |
|
} else { |
|
let s = self.ast_map.node_to_string(n.data.id()); |
|
let s = replace_newline_with_backslash_l(s); |
|
dot::LabelText::EscStr(s.into_cow()) |
|
} |
|
} |
|
fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> { |
|
let mut label = String::new(); |
|
if !self.labelled_edges { |
|
return dot::LabelText::EscStr(label.into_cow()); |
|
} |
|
let mut put_one = false; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(e.data.exiting_scopes.iter().enumerate()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some((i, |
|
&node_id)) |
|
=> { |
|
if put_one { |
|
label.push_str(",\\l"); |
|
} else { put_one = true; } |
|
let s = |
|
self.ast_map.node_to_string(node_id); |
|
let s = |
|
replace_newline_with_backslash_l(s); |
|
label.push_str(&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["exiting scope_", |
|
" "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&i, |
|
&&s[..]) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
}))); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
dot::LabelText::EscStr(label.into_cow()) |
|
} |
|
} |
|
impl <'a> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for &'a cfg::CFG |
|
{ |
|
fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { |
|
let mut v = Vec::new(); |
|
self.graph.each_node(|i, nd| { v.push((i, nd)); true }); |
|
v.into_cow() |
|
} |
|
fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { |
|
self.graph.all_edges().iter().collect() |
|
} |
|
fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { |
|
let i = edge.source(); |
|
(i, self.graph.node(i)) |
|
} |
|
fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { |
|
let i = edge.target(); |
|
(i, self.graph.node(i)) |
|
} |
|
} |
|
impl <'a, 'ast> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for |
|
LabelledCFG<'a, 'ast> { |
|
fn nodes(&'a self) -> dot::Nodes<'a, Node<'a>> { |
|
self.cfg.nodes() |
|
} |
|
fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> { |
|
self.cfg.edges() |
|
} |
|
fn source(&'a self, edge: &Edge<'a>) -> Node<'a> { |
|
self.cfg.source(edge) |
|
} |
|
fn target(&'a self, edge: &Edge<'a>) -> Node<'a> { |
|
self.cfg.target(edge) |
|
} |
|
} |
|
} |
|
pub struct CFG { |
|
pub graph: CFGGraph, |
|
pub entry: CFGIndex, |
|
pub exit: CFGIndex, |
|
} |
|
pub enum CFGNodeData { |
|
AST(ast::NodeId), |
|
Entry, |
|
Exit, |
|
Dummy, |
|
Unreachable, |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for CFGNodeData { |
|
#[inline] |
|
fn eq(&self, __arg_0: &CFGNodeData) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&CFGNodeData::AST(ref __self_0), |
|
&CFGNodeData::AST(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&CFGNodeData::Entry, &CFGNodeData::Entry) => |
|
true, |
|
(&CFGNodeData::Exit, &CFGNodeData::Exit) => true, |
|
(&CFGNodeData::Dummy, &CFGNodeData::Dummy) => |
|
true, |
|
(&CFGNodeData::Unreachable, |
|
&CFGNodeData::Unreachable) => true, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &CFGNodeData) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&CFGNodeData::AST(ref __self_0), |
|
&CFGNodeData::AST(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&CFGNodeData::Entry, &CFGNodeData::Entry) => |
|
false, |
|
(&CFGNodeData::Exit, &CFGNodeData::Exit) => false, |
|
(&CFGNodeData::Dummy, &CFGNodeData::Dummy) => |
|
false, |
|
(&CFGNodeData::Unreachable, |
|
&CFGNodeData::Unreachable) => false, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for CFGNodeData { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&CFGNodeData::AST(ref __self_0),) => |
|
__arg_0.debug_tuple("AST").field(&&(*__self_0)).finish(), |
|
(&CFGNodeData::Entry,) => |
|
__arg_0.debug_tuple("Entry").finish(), |
|
(&CFGNodeData::Exit,) => |
|
__arg_0.debug_tuple("Exit").finish(), |
|
(&CFGNodeData::Dummy,) => |
|
__arg_0.debug_tuple("Dummy").finish(), |
|
(&CFGNodeData::Unreachable,) => |
|
__arg_0.debug_tuple("Unreachable").finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for CFGNodeData { |
|
#[inline] |
|
fn clone(&self) -> CFGNodeData { |
|
match (&*self,) { |
|
(&CFGNodeData::AST(ref __self_0),) => |
|
CFGNodeData::AST(::std::clone::Clone::clone(&(*__self_0))), |
|
(&CFGNodeData::Entry,) => CFGNodeData::Entry, |
|
(&CFGNodeData::Exit,) => CFGNodeData::Exit, |
|
(&CFGNodeData::Dummy,) => CFGNodeData::Dummy, |
|
(&CFGNodeData::Unreachable,) => CFGNodeData::Unreachable, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for CFGNodeData { } |
|
impl CFGNodeData { |
|
pub fn id(&self) -> ast::NodeId { |
|
match *self { |
|
CFGNodeData::AST(id) => { id } |
|
_ => { ast::DUMMY_NODE_ID } |
|
} |
|
} |
|
} |
|
pub struct CFGEdgeData { |
|
pub exiting_scopes: Vec<ast::NodeId>, |
|
} |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for CFGEdgeData { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match *self { |
|
CFGEdgeData { exiting_scopes: ref __self_0_0 } => |
|
__arg_0.debug_struct("CFGEdgeData").field("exiting_scopes", |
|
&&(*__self_0_0)).finish(), |
|
} |
|
} |
|
} |
|
pub type CFGIndex = graph::NodeIndex; |
|
pub type CFGGraph = graph::Graph<CFGNodeData, CFGEdgeData>; |
|
pub type CFGNode = graph::Node<CFGNodeData>; |
|
pub type CFGEdge = graph::Edge<CFGEdgeData>; |
|
impl CFG { |
|
pub fn new(tcx: &ty::ctxt, blk: &hir::Block) -> CFG { |
|
construct::construct(tcx, blk) |
|
} |
|
pub fn node_is_reachable(&self, id: ast::NodeId) -> bool { |
|
self.graph.depth_traverse(self.entry).any(|idx| |
|
self.graph.node_data(idx).id() |
|
== id) |
|
} |
|
} |
|
} |
|
pub mod check_const { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
use middle::ty::cast::{CastKind}; |
|
use middle::const_eval; |
|
use middle::const_eval::EvalHint::ExprTypeChecked; |
|
use middle::def; |
|
use middle::def_id::DefId; |
|
use middle::expr_use_visitor as euv; |
|
use middle::infer; |
|
use middle::mem_categorization as mc; |
|
use middle::mem_categorization::Categorization; |
|
use middle::traits; |
|
use middle::ty::{self, Ty}; |
|
use util::nodemap::NodeMap; |
|
use rustc_front::hir; |
|
use syntax::ast; |
|
use syntax::codemap::Span; |
|
use syntax::feature_gate::UnstableFeatures; |
|
use rustc_front::intravisit::{self, FnKind, Visitor}; |
|
use std::collections::hash_map::Entry; |
|
use std::cmp::Ordering; |
|
pub struct ConstQualif { |
|
bits: u8, |
|
} |
|
#[automatically_derived] |
|
impl ::std::hash::Hash for ConstQualif { |
|
fn hash<__H: ::std::hash::Hasher>(&self, __arg_0: &mut __H) |
|
-> () { |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => { |
|
::std::hash::Hash::hash(&(*__self_0_0), __arg_0); |
|
} |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::Ord for ConstQualif { |
|
#[inline] |
|
fn cmp(&self, __arg_0: &ConstQualif) -> ::std::cmp::Ordering { |
|
match *__arg_0 { |
|
ConstQualif { bits: ref __self_1_0 } => |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => { |
|
let __test = |
|
::std::cmp::Ord::cmp(&(*__self_0_0), |
|
&(*__self_1_0)); |
|
if __test == ::std::cmp::Ordering::Equal { |
|
::std::cmp::Ordering::Equal |
|
} else { __test } |
|
} |
|
}, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialOrd for ConstQualif { |
|
#[inline] |
|
fn partial_cmp(&self, __arg_0: &ConstQualif) |
|
-> ::std::option::Option<::std::cmp::Ordering> { |
|
match *__arg_0 { |
|
ConstQualif { bits: ref __self_1_0 } => |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => { |
|
let __test = |
|
::std::cmp::PartialOrd::partial_cmp(&(*__self_0_0), |
|
&(*__self_1_0)); |
|
if __test == |
|
::std::option::Option::Some(::std::cmp::Ordering::Equal) |
|
{ |
|
::std::option::Option::Some(::std::cmp::Ordering::Equal) |
|
} else { __test } |
|
} |
|
}, |
|
} |
|
} |
|
#[inline] |
|
fn lt(&self, __arg_0: &ConstQualif) -> bool { |
|
match *__arg_0 { |
|
ConstQualif { bits: ref __self_1_0 } => |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => |
|
(*__self_0_0) < (*__self_1_0) || |
|
!((*__self_1_0) < (*__self_0_0)) && false, |
|
}, |
|
} |
|
} |
|
#[inline] |
|
fn le(&self, __arg_0: &ConstQualif) -> bool { |
|
match *__arg_0 { |
|
ConstQualif { bits: ref __self_1_0 } => |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => |
|
(*__self_0_0) < (*__self_1_0) || |
|
!((*__self_1_0) < (*__self_0_0)) && true, |
|
}, |
|
} |
|
} |
|
#[inline] |
|
fn gt(&self, __arg_0: &ConstQualif) -> bool { |
|
match *__arg_0 { |
|
ConstQualif { bits: ref __self_1_0 } => |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => |
|
(*__self_0_0) > (*__self_1_0) || |
|
!((*__self_1_0) > (*__self_0_0)) && false, |
|
}, |
|
} |
|
} |
|
#[inline] |
|
fn ge(&self, __arg_0: &ConstQualif) -> bool { |
|
match *__arg_0 { |
|
ConstQualif { bits: ref __self_1_0 } => |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => |
|
(*__self_0_0) > (*__self_1_0) || |
|
!((*__self_1_0) > (*__self_0_0)) && true, |
|
}, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for ConstQualif { |
|
#[inline] |
|
fn clone(&self) -> ConstQualif { |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => |
|
ConstQualif{bits: |
|
::std::clone::Clone::clone(&(*__self_0_0)),}, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::Eq for ConstQualif { |
|
#[inline] |
|
#[doc(hidden)] |
|
fn assert_receiver_is_total_eq(&self) -> () { |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => { |
|
(*__self_0_0).assert_receiver_is_total_eq(); |
|
} |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for ConstQualif { |
|
#[inline] |
|
fn eq(&self, __arg_0: &ConstQualif) -> bool { |
|
match *__arg_0 { |
|
ConstQualif { bits: ref __self_1_0 } => |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => |
|
true && (*__self_0_0) == (*__self_1_0), |
|
}, |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &ConstQualif) -> bool { |
|
match *__arg_0 { |
|
ConstQualif { bits: ref __self_1_0 } => |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => |
|
false || (*__self_0_0) != (*__self_1_0), |
|
}, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for ConstQualif { } |
|
#[automatically_derived] |
|
impl ::rustc_serialize::Decodable for ConstQualif { |
|
fn decode<__D: ::rustc_serialize::Decoder>(__arg_0: &mut __D) |
|
-> ::std::result::Result<ConstQualif, __D::Error> { |
|
__arg_0.read_struct("ConstQualif", 1usize, |_d| -> _ { |
|
::std::result::Result::Ok(ConstQualif{bits: |
|
match _d.read_struct_field("bits", |
|
0usize, |
|
::rustc_serialize::Decodable::decode) |
|
{ |
|
::std::result::Result::Ok(__try_var) |
|
=> |
|
__try_var, |
|
::std::result::Result::Err(__try_var) |
|
=> |
|
return ::std::result::Result::Err(__try_var), |
|
},}) |
|
}) |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::rustc_serialize::Encodable for ConstQualif { |
|
fn encode<__S: ::rustc_serialize::Encoder>(&self, |
|
__arg_0: &mut __S) |
|
-> ::std::result::Result<(), __S::Error> { |
|
match *self { |
|
ConstQualif { bits: ref __self_0_0 } => |
|
__arg_0.emit_struct("ConstQualif", 1usize, |_e| -> _ { |
|
return _e.emit_struct_field("bits", |
|
0usize, |
|
|_e| -> _ |
|
{ |
|
(*__self_0_0).encode(_e) |
|
}); }), |
|
} |
|
} |
|
} |
|
impl ConstQualif { |
|
pub const |
|
MUTABLE_MEM: |
|
ConstQualif |
|
= |
|
ConstQualif{bits: 1 << 0,}; |
|
pub const |
|
NEEDS_DROP: |
|
ConstQualif |
|
= |
|
ConstQualif{bits: 1 << 1,}; |
|
pub const |
|
PREFER_IN_PLACE: |
|
ConstQualif |
|
= |
|
ConstQualif{bits: 1 << 2,}; |
|
pub const |
|
NON_ZERO_SIZED: |
|
ConstQualif |
|
= |
|
ConstQualif{bits: 1 << 3,}; |
|
pub const |
|
HAS_STATIC_BORROWS: |
|
ConstQualif |
|
= |
|
ConstQualif{bits: 1 << 4,}; |
|
pub const |
|
NOT_CONST: |
|
ConstQualif |
|
= |
|
ConstQualif{bits: 1 << 5,}; |
|
pub const |
|
NON_STATIC_BORROWS: |
|
ConstQualif |
|
= |
|
ConstQualif{bits: |
|
ConstQualif::MUTABLE_MEM.bits | |
|
ConstQualif::NEEDS_DROP.bits | |
|
ConstQualif::NOT_CONST.bits,}; |
|
/// Returns an empty set of flags. |
|
#[inline] |
|
pub fn empty() -> ConstQualif { ConstQualif{bits: 0,} } |
|
/// Returns the set containing all flags. |
|
#[inline] |
|
pub fn all() -> ConstQualif { |
|
ConstQualif{bits: |
|
1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | |
|
1 << 5 | |
|
ConstQualif::MUTABLE_MEM.bits | |
|
ConstQualif::NEEDS_DROP.bits | |
|
ConstQualif::NOT_CONST.bits,} |
|
} |
|
/// Returns the raw value of the flags currently stored. |
|
#[inline] |
|
pub fn bits(&self) -> u8 { self.bits } |
|
/// Convert from underlying bit representation, unless that |
|
/// representation contains bits that do not correspond to a flag. |
|
#[inline] |
|
pub fn from_bits(bits: u8) -> ::std::option::Option<ConstQualif> { |
|
if (bits & !ConstQualif::all().bits()) != 0 { |
|
::std::option::Option::None |
|
} else { |
|
::std::option::Option::Some(ConstQualif{bits: bits,}) |
|
} |
|
} |
|
/// Convert from underlying bit representation, dropping any bits |
|
/// that do not correspond to flags. |
|
#[inline] |
|
pub fn from_bits_truncate(bits: u8) -> ConstQualif { |
|
ConstQualif{bits: bits,} & ConstQualif::all() |
|
} |
|
/// Returns `true` if no flags are currently stored. |
|
#[inline] |
|
pub fn is_empty(&self) -> bool { *self == ConstQualif::empty() } |
|
/// Returns `true` if all flags are currently set. |
|
#[inline] |
|
pub fn is_all(&self) -> bool { *self == ConstQualif::all() } |
|
/// Returns `true` if there are flags common to both `self` and `other`. |
|
#[inline] |
|
pub fn intersects(&self, other: ConstQualif) -> bool { |
|
!(*self & other).is_empty() |
|
} |
|
/// Returns `true` all of the flags in `other` are contained within `self`. |
|
#[inline] |
|
pub fn contains(&self, other: ConstQualif) -> bool { |
|
(*self & other) == other |
|
} |
|
/// Inserts the specified flags in-place. |
|
#[inline] |
|
pub fn insert(&mut self, other: ConstQualif) { |
|
self.bits |= other.bits; |
|
} |
|
/// Removes the specified flags in-place. |
|
#[inline] |
|
pub fn remove(&mut self, other: ConstQualif) { |
|
self.bits &= !other.bits; |
|
} |
|
/// Toggles the specified flags in-place. |
|
#[inline] |
|
pub fn toggle(&mut self, other: ConstQualif) { |
|
self.bits ^= other.bits; |
|
} |
|
} |
|
impl ::std::ops::BitOr for ConstQualif { |
|
type |
|
Output |
|
= |
|
ConstQualif; |
|
/// Returns the union of the two sets of flags. |
|
#[inline] |
|
fn bitor(self, other: ConstQualif) -> ConstQualif { |
|
ConstQualif{bits: self.bits | other.bits,} |
|
} |
|
} |
|
impl ::std::ops::BitXor for ConstQualif { |
|
type |
|
Output |
|
= |
|
ConstQualif; |
|
/// Returns the left flags, but with all the right flags toggled. |
|
#[inline] |
|
fn bitxor(self, other: ConstQualif) -> ConstQualif { |
|
ConstQualif{bits: self.bits ^ other.bits,} |
|
} |
|
} |
|
impl ::std::ops::BitAnd for ConstQualif { |
|
type |
|
Output |
|
= |
|
ConstQualif; |
|
/// Returns the intersection between the two sets of flags. |
|
#[inline] |
|
fn bitand(self, other: ConstQualif) -> ConstQualif { |
|
ConstQualif{bits: self.bits & other.bits,} |
|
} |
|
} |
|
impl ::std::ops::Sub for ConstQualif { |
|
type |
|
Output |
|
= |
|
ConstQualif; |
|
/// Returns the set difference of the two sets of flags. |
|
#[inline] |
|
fn sub(self, other: ConstQualif) -> ConstQualif { |
|
ConstQualif{bits: self.bits & !other.bits,} |
|
} |
|
} |
|
impl ::std::ops::Not for ConstQualif { |
|
type |
|
Output |
|
= |
|
ConstQualif; |
|
/// Returns the complement of this set of flags. |
|
#[inline] |
|
fn not(self) -> ConstQualif { |
|
ConstQualif{bits: !self.bits,} & ConstQualif::all() |
|
} |
|
} |
|
enum Mode { Const, ConstFn, Static, StaticMut, Var, } |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for Mode { |
|
#[inline] |
|
fn eq(&self, __arg_0: &Mode) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&Mode::Const, &Mode::Const) => true, |
|
(&Mode::ConstFn, &Mode::ConstFn) => true, |
|
(&Mode::Static, &Mode::Static) => true, |
|
(&Mode::StaticMut, &Mode::StaticMut) => true, |
|
(&Mode::Var, &Mode::Var) => true, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &Mode) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&Mode::Const, &Mode::Const) => false, |
|
(&Mode::ConstFn, &Mode::ConstFn) => false, |
|
(&Mode::Static, &Mode::Static) => false, |
|
(&Mode::StaticMut, &Mode::StaticMut) => false, |
|
(&Mode::Var, &Mode::Var) => false, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::Eq for Mode { |
|
#[inline] |
|
#[doc(hidden)] |
|
fn assert_receiver_is_total_eq(&self) -> () { |
|
match (&*self,) { |
|
(&Mode::Const,) => { } |
|
(&Mode::ConstFn,) => { } |
|
(&Mode::Static,) => { } |
|
(&Mode::StaticMut,) => { } |
|
(&Mode::Var,) => { } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::fmt::Debug for Mode { |
|
fn fmt(&self, __arg_0: &mut ::std::fmt::Formatter) |
|
-> ::std::fmt::Result { |
|
match (&*self,) { |
|
(&Mode::Const,) => __arg_0.debug_tuple("Const").finish(), |
|
(&Mode::ConstFn,) => |
|
__arg_0.debug_tuple("ConstFn").finish(), |
|
(&Mode::Static,) => |
|
__arg_0.debug_tuple("Static").finish(), |
|
(&Mode::StaticMut,) => |
|
__arg_0.debug_tuple("StaticMut").finish(), |
|
(&Mode::Var,) => __arg_0.debug_tuple("Var").finish(), |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for Mode { |
|
#[inline] |
|
fn clone(&self) -> Mode { |
|
match (&*self,) { |
|
(&Mode::Const,) => Mode::Const, |
|
(&Mode::ConstFn,) => Mode::ConstFn, |
|
(&Mode::Static,) => Mode::Static, |
|
(&Mode::StaticMut,) => Mode::StaticMut, |
|
(&Mode::Var,) => Mode::Var, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for Mode { } |
|
struct CheckCrateVisitor<'a, 'tcx:'a> { |
|
tcx: &'a ty::ctxt<'tcx>, |
|
mode: Mode, |
|
qualif: ConstQualif, |
|
rvalue_borrows: NodeMap<hir::Mutability>, |
|
} |
|
impl <'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { |
|
fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R where |
|
F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>) -> R { |
|
let (old_mode, old_qualif) = (self.mode, self.qualif); |
|
self.mode = mode; |
|
self.qualif = ConstQualif::empty(); |
|
let r = f(self); |
|
self.mode = old_mode; |
|
self.qualif = old_qualif; |
|
r |
|
} |
|
fn with_euv<'b, F, |
|
R>(&'b mut self, item_id: Option<ast::NodeId>, f: F) |
|
-> R where |
|
F: for<'t>FnOnce(&mut euv::ExprUseVisitor<'b, 't, 'b, 'tcx>) -> |
|
R { |
|
let param_env = |
|
match item_id { |
|
Some(item_id) => |
|
ty::ParameterEnvironment::for_item(self.tcx, item_id), |
|
None => self.tcx.empty_parameter_environment(), |
|
}; |
|
let infcx = |
|
infer::new_infer_ctxt(self.tcx, &self.tcx.tables, |
|
Some(param_env), false); |
|
f(&mut euv::ExprUseVisitor::new(self, &infcx)) |
|
} |
|
fn global_expr(&mut self, mode: Mode, expr: &hir::Expr) |
|
-> ConstQualif { |
|
if !(mode != Mode::Var) { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: mode != Mode::Var", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, u32) |
|
= |
|
("src/librustc/middle/check_const.rs", |
|
132u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) { |
|
Entry::Occupied(entry) => return *entry.get(), |
|
Entry::Vacant(entry) => { |
|
entry.insert(ConstQualif::empty()); |
|
} |
|
} |
|
self.with_mode(mode, |this| { |
|
this.with_euv(None, |
|
|euv| euv.consume_expr(expr)); |
|
this.visit_expr(expr); this.qualif }) |
|
} |
|
fn fn_like(&mut self, fk: FnKind, fd: &hir::FnDecl, |
|
b: &hir::Block, s: Span, fn_id: ast::NodeId) |
|
-> ConstQualif { |
|
match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) { |
|
Entry::Occupied(entry) => return *entry.get(), |
|
Entry::Vacant(entry) => { |
|
entry.insert(ConstQualif::empty()); |
|
} |
|
} |
|
let mode = |
|
match fk { |
|
FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _) |
|
=> { |
|
Mode::ConstFn |
|
} |
|
FnKind::Method(_, m, _) => { |
|
if m.constness == hir::Constness::Const { |
|
Mode::ConstFn |
|
} else { Mode::Var } |
|
} |
|
_ => Mode::Var, |
|
}; |
|
if mode == Mode::ConstFn { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&fd.inputs) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(arg) => { |
|
match arg.pat.node { |
|
hir::PatWild => { } |
|
hir::PatIdent(hir::BindByValue(hir::MutImmutable), |
|
_, None) => { |
|
} |
|
_ => { |
|
{ |
|
(); |
|
self.tcx.sess.span_err_with_code(arg.pat.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["arguments of constant functions can only be immutable by-value bindings"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0022") |
|
}; |
|
} |
|
} |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
let qualif = |
|
self.with_mode(mode, |this| { |
|
this.with_euv(Some(fn_id), |
|
|euv| euv.walk_fn(fd, b)); |
|
intravisit::walk_fn(this, fk, fd, b, s); |
|
this.qualif }); |
|
let qualif = |
|
qualif & |
|
(ConstQualif::NON_ZERO_SIZED | |
|
ConstQualif::PREFER_IN_PLACE); |
|
self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif); |
|
qualif |
|
} |
|
fn add_qualif(&mut self, qualif: ConstQualif) { |
|
self.qualif = self.qualif | qualif; |
|
} |
|
/// Returns true if the call is to a const fn or method. |
|
fn handle_const_fn_call(&mut self, expr: &hir::Expr, |
|
def_id: DefId, ret_ty: Ty<'tcx>) -> bool { |
|
match const_eval::lookup_const_fn_by_id(self.tcx, def_id) { |
|
Some(fn_like) => { |
|
if self.mode != Mode::Var && |
|
!self.tcx.sess.features.borrow().const_fn && |
|
!self.tcx.sess.codemap().span_allows_unstable(expr.span) |
|
{ |
|
self.tcx.sess.span_err(expr.span, |
|
"const fns are an unstable feature"); |
|
{ |
|
(self.tcx.sess).fileline_help(expr.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["in Nightly builds, add `#![feature(const_fn)]` to the crate attributes to enable"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
}))) |
|
}; |
|
} |
|
let qualif = |
|
self.fn_like(fn_like.kind(), fn_like.decl(), |
|
fn_like.body(), fn_like.span(), |
|
fn_like.id()); |
|
self.add_qualif(qualif); |
|
if ret_ty.type_contents(self.tcx).interior_unsafe() { |
|
self.add_qualif(ConstQualif::MUTABLE_MEM); |
|
} |
|
true |
|
} |
|
_ => { false } |
|
} |
|
} |
|
fn record_borrow(&mut self, id: ast::NodeId, |
|
mutbl: hir::Mutability) { |
|
match self.rvalue_borrows.entry(id) { |
|
Entry::Occupied(mut entry) => { |
|
if mutbl == hir::MutMutable { entry.insert(mutbl); } |
|
} |
|
Entry::Vacant(entry) => { entry.insert(mutbl); } |
|
} |
|
} |
|
fn msg(&self) -> &'static str { |
|
match self.mode { |
|
Mode::Const => "constant", |
|
Mode::ConstFn => "constant function", |
|
Mode::StaticMut | Mode::Static => "static", |
|
Mode::Var => { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/middle/check_const.rs", |
|
273u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
fn check_static_mut_type(&self, e: &hir::Expr) { |
|
let node_ty = self.tcx.node_id_to_type(e.id); |
|
let tcontents = node_ty.type_contents(self.tcx); |
|
let suffix = |
|
if tcontents.has_dtor() { |
|
"destructors" |
|
} else if tcontents.owns_owned() { |
|
"boxes" |
|
} else { return }; |
|
{ |
|
(); |
|
self.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mutable statics are not allowed to have "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&suffix,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0397") |
|
}; |
|
} |
|
fn check_static_type(&self, e: &hir::Expr) { |
|
let ty = self.tcx.node_id_to_type(e.id); |
|
let infcx = |
|
infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, |
|
false); |
|
let cause = |
|
traits::ObligationCause::new(e.span, e.id, |
|
traits::SharedStatic); |
|
let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut(); |
|
fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, |
|
cause); |
|
match fulfill_cx.select_all_or_error(&infcx) { |
|
Ok(()) => { } |
|
Err(ref errors) => { |
|
traits::report_fulfillment_errors(&infcx, errors); |
|
} |
|
} |
|
} |
|
} |
|
impl <'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { |
|
fn visit_item(&mut self, i: &hir::Item) { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 310u32, |
|
file: |
|
"src/librustc/middle/check_const.rs", |
|
module_path: |
|
"rustc::middle::check_const",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::check_const") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["visit_item(item=", |
|
")"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.tcx.map.node_to_string(i.id),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
{ |
|
match (&(self.mode), &(Mode::Var)) { |
|
(left_val, right_val) => { |
|
if !(*left_val == *right_val) { |
|
{ |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["assertion failed: `(left == right)` (left: `", |
|
"`, right: `", |
|
"`)"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&left_val, |
|
&right_val) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/middle/check_const.rs", |
|
311u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
}; |
|
match i.node { |
|
hir::ItemStatic(_, hir::MutImmutable, ref expr) => { |
|
self.check_static_type(&**expr); |
|
self.global_expr(Mode::Static, &**expr); |
|
} |
|
hir::ItemStatic(_, hir::MutMutable, ref expr) => { |
|
self.check_static_mut_type(&**expr); |
|
self.global_expr(Mode::StaticMut, &**expr); |
|
} |
|
hir::ItemConst(_, ref expr) => { |
|
self.global_expr(Mode::Const, &**expr); |
|
} |
|
hir::ItemEnum(ref enum_definition, _) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&enum_definition.variants) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(var) |
|
=> { |
|
match var.node.disr_expr { |
|
Some(ref ex) => { |
|
self.global_expr(Mode::Const, |
|
&**ex); |
|
} |
|
_ => (), |
|
} |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
_ => { intravisit::walk_item(self, i); } |
|
} |
|
} |
|
fn visit_trait_item(&mut self, t: &'v hir::TraitItem) { |
|
match t.node { |
|
hir::ConstTraitItem(_, ref default) => { |
|
match *default { |
|
Some(ref expr) => { |
|
self.global_expr(Mode::Const, &*expr); |
|
} |
|
_ => { intravisit::walk_trait_item(self, t); } |
|
} |
|
} |
|
_ => |
|
self.with_mode(Mode::Var, |
|
|v| intravisit::walk_trait_item(v, t)), |
|
} |
|
} |
|
fn visit_impl_item(&mut self, i: &'v hir::ImplItem) { |
|
match i.node { |
|
hir::ImplItemKind::Const(_, ref expr) => { |
|
self.global_expr(Mode::Const, &*expr); |
|
} |
|
_ => |
|
self.with_mode(Mode::Var, |
|
|v| intravisit::walk_impl_item(v, i)), |
|
} |
|
} |
|
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, |
|
b: &'v hir::Block, s: Span, fn_id: ast::NodeId) { |
|
self.fn_like(fk, fd, b, s, fn_id); |
|
} |
|
fn visit_pat(&mut self, p: &hir::Pat) { |
|
match p.node { |
|
hir::PatLit(ref lit) => { |
|
self.global_expr(Mode::Const, &**lit); |
|
} |
|
hir::PatRange(ref start, ref end) => { |
|
self.global_expr(Mode::Const, &**start); |
|
self.global_expr(Mode::Const, &**end); |
|
match const_eval::compare_lit_exprs(self.tcx, start, |
|
end) { |
|
Some(Ordering::Less) | Some(Ordering::Equal) => { |
|
} |
|
Some(Ordering::Greater) => { |
|
{ |
|
(); |
|
self.tcx.sess.span_err_with_code(start.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["lower range bound must be less than or equal to upper"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0030") |
|
}; |
|
} |
|
None => { |
|
self.tcx.sess.delay_span_bug(start.span, |
|
"non-constant path in constant expr"); |
|
} |
|
} |
|
} |
|
_ => intravisit::walk_pat(self, p), |
|
} |
|
} |
|
fn visit_block(&mut self, block: &hir::Block) { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&block.stmts) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(stmt) => { |
|
let span = |
|
match stmt.node { |
|
hir::StmtDecl(ref decl, _) => |
|
{ |
|
match decl.node { |
|
hir::DeclLocal(_) => |
|
decl.span, |
|
hir::DeclItem(_) => |
|
continue , |
|
} |
|
} |
|
hir::StmtExpr(ref expr, _) => |
|
expr.span, |
|
hir::StmtSemi(ref semi, _) => |
|
semi.span, |
|
}; |
|
self.add_qualif(ConstQualif::NOT_CONST); |
|
if self.mode != Mode::Var { |
|
{ |
|
(); |
|
self.tcx.sess.span_err_with_code(span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["blocks in ", |
|
"s are limited to items and tail expressions"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0016") |
|
}; |
|
} |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
intravisit::walk_block(self, block); |
|
} |
|
fn visit_expr(&mut self, ex: &hir::Expr) { |
|
let mut outer = self.qualif; |
|
self.qualif = ConstQualif::empty(); |
|
let node_ty = self.tcx.node_id_to_type(ex.id); |
|
check_expr(self, ex, node_ty); |
|
check_adjustments(self, ex); |
|
match ex.node { |
|
hir::ExprCall(ref callee, ref args) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(args) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(arg) |
|
=> { |
|
self.visit_expr(&**arg) |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
let inner = self.qualif; |
|
self.visit_expr(&**callee); |
|
let added = self.qualif - inner; |
|
self.qualif = |
|
inner | (added - ConstQualif::NON_ZERO_SIZED); |
|
} |
|
hir::ExprRepeat(ref element, _) => { |
|
self.visit_expr(&**element); |
|
let count = |
|
match node_ty.sty { |
|
ty::TyArray(_, n) => n, |
|
_ => { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/middle/check_const.rs", |
|
445u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
}; |
|
if count == 0 { |
|
self.qualif.remove(ConstQualif::NON_ZERO_SIZED | |
|
ConstQualif::PREFER_IN_PLACE); |
|
} |
|
} |
|
hir::ExprMatch(ref discr, ref arms, _) => { |
|
let mut borrow = None; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(arms.iter().flat_map(|arm| |
|
&arm.pats)) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(pat) |
|
=> { |
|
let pat_borrow = |
|
self.rvalue_borrows.remove(&pat.id); |
|
match (borrow, pat_borrow) { |
|
(None, _) | |
|
(_, Some(hir::MutMutable)) |
|
=> { |
|
borrow = pat_borrow; |
|
} |
|
_ => { } |
|
} |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
match borrow { |
|
Some(mutbl) => { |
|
self.record_borrow(discr.id, mutbl); |
|
} |
|
_ => (), |
|
} |
|
intravisit::walk_expr(self, ex); |
|
} |
|
hir::ExprBinary(op, _, _) => { |
|
intravisit::walk_expr(self, ex); |
|
let div_or_rem = |
|
op.node == hir::BiDiv || op.node == hir::BiRem; |
|
match node_ty.sty { |
|
ty::TyUint(_) | ty::TyInt(_) if div_or_rem => { |
|
if !self.qualif.intersects(ConstQualif::NOT_CONST) |
|
{ |
|
match const_eval::eval_const_expr_partial(self.tcx, |
|
ex, |
|
ExprTypeChecked, |
|
None) |
|
{ |
|
Ok(_) => { } |
|
Err(msg) => { |
|
self.tcx.sess.add_lint(::lint::builtin::CONST_ERR, |
|
ex.id, |
|
msg.span, |
|
msg.description().into_owned()) |
|
} |
|
} |
|
} |
|
} |
|
_ => { } |
|
} |
|
} |
|
_ => intravisit::walk_expr(self, ex), |
|
} |
|
match self.rvalue_borrows.remove(&ex.id) { |
|
Some(hir::MutImmutable) => { |
|
let tc = node_ty.type_contents(self.tcx); |
|
if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && |
|
tc.interior_unsafe() { |
|
outer = outer | ConstQualif::NOT_CONST; |
|
if self.mode != Mode::Var { |
|
{ |
|
(); |
|
self.tcx.sess.span_err_with_code(ex.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["cannot borrow a constant which contains interior mutability, create a static instead"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0492") |
|
}; |
|
} |
|
} |
|
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) |
|
{ |
|
self.qualif = |
|
self.qualif - ConstQualif::PREFER_IN_PLACE; |
|
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS); |
|
} |
|
} |
|
Some(hir::MutMutable) => { |
|
if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) |
|
{ |
|
if self.mode == Mode::Var { |
|
outer = outer | ConstQualif::NOT_CONST; |
|
self.add_qualif(ConstQualif::MUTABLE_MEM); |
|
} else { |
|
{ |
|
(); |
|
self.tcx.sess.span_err_with_code(ex.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["references in ", |
|
"s may only refer to immutable values"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0017") |
|
} |
|
} |
|
} |
|
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) |
|
{ |
|
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS); |
|
} |
|
} |
|
None => { } |
|
} |
|
self.tcx.const_qualif_map.borrow_mut().insert(ex.id, |
|
self.qualif); |
|
self.qualif = |
|
outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS); |
|
} |
|
} |
|
/// This function is used to enforce the constraints on |
|
/// const/static items. It walks through the *value* |
|
/// of the item walking down the expression and evaluating |
|
/// every nested expression. If the expression is not part |
|
/// of a const/static item, it is qualified for promotion |
|
/// instead of producing errors. |
|
fn check_expr<'a, |
|
'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, |
|
e: &hir::Expr, node_ty: Ty<'tcx>) { |
|
match node_ty.sty { |
|
ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => |
|
{ |
|
v.add_qualif(ConstQualif::NEEDS_DROP); |
|
if v.mode != Mode::Var { |
|
{ |
|
(); |
|
v.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["", |
|
"s are not allowed to have destructors"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0493") |
|
}; |
|
} |
|
} |
|
_ => { } |
|
} |
|
let method_call = ty::MethodCall::expr(e.id); |
|
match e.node { |
|
hir::ExprUnary(..) | hir::ExprBinary(..) | hir::ExprIndex(..) |
|
if v.tcx.tables.borrow().method_map.contains_key(&method_call) |
|
=> { |
|
v.add_qualif(ConstQualif::NOT_CONST); |
|
if v.mode != Mode::Var { |
|
{ |
|
(); |
|
v.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["user-defined operators are not allowed in ", |
|
"s"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0011") |
|
}; |
|
} |
|
} |
|
hir::ExprBox(_) => { |
|
v.add_qualif(ConstQualif::NOT_CONST); |
|
if v.mode != Mode::Var { |
|
{ |
|
(); |
|
v.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["allocations are not allowed in ", |
|
"s"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0010") |
|
}; |
|
} |
|
} |
|
hir::ExprUnary(op, ref inner) => { |
|
match v.tcx.node_id_to_type(inner.id).sty { |
|
ty::TyRawPtr(_) => { |
|
if !(op == hir::UnDeref) { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: op == hir::UnDeref", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/middle/check_const.rs", |
|
584u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
v.add_qualif(ConstQualif::NOT_CONST); |
|
if v.mode != Mode::Var { |
|
{ |
|
(); |
|
v.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["raw pointers cannot be dereferenced in ", |
|
"s"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0396") |
|
}; |
|
} |
|
} |
|
_ => { } |
|
} |
|
} |
|
hir::ExprBinary(op, ref lhs, _) => { |
|
match v.tcx.node_id_to_type(lhs.id).sty { |
|
ty::TyRawPtr(_) => { |
|
if !(op.node == hir::BiEq || op.node == hir::BiNe |
|
|| op.node == hir::BiLe || |
|
op.node == hir::BiLt || |
|
op.node == hir::BiGe || |
|
op.node == hir::BiGt) { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: op.node == hir::BiEq || op.node == hir::BiNe || op.node == hir::BiLe ||\n op.node == hir::BiLt || op.node == hir::BiGe || op.node == hir::BiGt", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/middle/check_const.rs", |
|
598u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
v.add_qualif(ConstQualif::NOT_CONST); |
|
if v.mode != Mode::Var { |
|
{ |
|
(); |
|
v.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["raw pointers cannot be compared in ", |
|
"s"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0395") |
|
}; |
|
} |
|
} |
|
_ => { } |
|
} |
|
} |
|
hir::ExprCast(ref from, _) => { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 612u32, |
|
file: |
|
"src/librustc/middle/check_const.rs", |
|
module_path: |
|
"rustc::middle::check_const",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::check_const") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["Checking const cast(id=", |
|
")"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&from.id,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
match v.tcx.cast_kinds.borrow().get(&from.id) { |
|
None => |
|
v.tcx.sess.span_bug(e.span, "no kind for cast"), |
|
Some(&CastKind::PtrAddrCast) | |
|
Some(&CastKind::FnPtrAddrCast) => { |
|
v.add_qualif(ConstQualif::NOT_CONST); |
|
if v.mode != Mode::Var { |
|
{ |
|
(); |
|
v.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["raw pointers cannot be cast to integers in ", |
|
"s"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0018") |
|
}; |
|
} |
|
} |
|
_ => { } |
|
} |
|
} |
|
hir::ExprPath(..) => { |
|
let def = |
|
v.tcx.def_map.borrow().get(&e.id).map(|d| |
|
d.full_def()); |
|
match def { |
|
Some(def::DefVariant(_, _, _)) => { |
|
v.add_qualif(ConstQualif::NON_ZERO_SIZED); |
|
} |
|
Some(def::DefStruct(_)) => { |
|
match node_ty.sty { |
|
ty::TyBareFn(..) => { |
|
v.add_qualif(ConstQualif::NON_ZERO_SIZED); |
|
} |
|
_ => (), |
|
} |
|
} |
|
Some(def::DefFn(..)) | Some(def::DefMethod(..)) => { |
|
v.add_qualif(ConstQualif::NON_ZERO_SIZED); |
|
} |
|
Some(def::DefStatic(..)) => { |
|
match v.mode { |
|
Mode::Static | Mode::StaticMut => { } |
|
Mode::Const | Mode::ConstFn => { |
|
{ |
|
(); |
|
v.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["", |
|
"s cannot refer to other statics, insert an intermediate constant instead"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0013") |
|
}; |
|
} |
|
Mode::Var => |
|
v.add_qualif(ConstQualif::NOT_CONST), |
|
} |
|
} |
|
Some(def::DefConst(did)) | |
|
Some(def::DefAssociatedConst(did)) => { |
|
match const_eval::lookup_const_by_id(v.tcx, did, |
|
Some(e.id)) { |
|
Some(expr) => { |
|
let inner = |
|
v.global_expr(Mode::Const, expr); |
|
v.add_qualif(inner); |
|
} |
|
_ => { |
|
v.tcx.sess.span_bug(e.span, |
|
"DefConst or DefAssociatedConst doesn\'t point to a constant"); |
|
} |
|
} |
|
} |
|
Some(def::DefLocal(..)) if v.mode == Mode::ConstFn => |
|
{ |
|
v.add_qualif(ConstQualif::NOT_CONST | |
|
ConstQualif::NON_ZERO_SIZED); |
|
} |
|
def => { |
|
v.add_qualif(ConstQualif::NOT_CONST); |
|
if v.mode != Mode::Var { |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 672u32, |
|
file: |
|
"src/librustc/middle/check_const.rs", |
|
module_path: |
|
"rustc::middle::check_const",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) |
|
&& |
|
lvl <= ::log::log_level() |
|
&& |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::check_const") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["(checking const) found bad def: "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&def,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
{ |
|
(); |
|
v.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["paths in ", |
|
"s may only refer to constants or functions"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0014") |
|
}; |
|
} |
|
} |
|
} |
|
} |
|
hir::ExprCall(ref callee, _) => { |
|
let mut callee = &**callee; |
|
loop { |
|
callee = |
|
match callee.node { |
|
hir::ExprBlock(ref block) => |
|
match block.expr { |
|
Some(ref tail) => &**tail, |
|
None => break , |
|
}, |
|
_ => break , |
|
}; |
|
} |
|
let def = |
|
v.tcx.def_map.borrow().get(&callee.id).map(|d| |
|
d.full_def()); |
|
let is_const = |
|
match def { |
|
Some(def::DefStruct(..)) => true, |
|
Some(def::DefVariant(..)) => { |
|
v.add_qualif(ConstQualif::NON_ZERO_SIZED); |
|
true |
|
} |
|
Some(def::DefFn(did, _)) => { |
|
v.handle_const_fn_call(e, did, node_ty) |
|
} |
|
Some(def::DefMethod(did)) => { |
|
match v.tcx.impl_or_trait_item(did).container() |
|
{ |
|
ty::ImplContainer(_) => { |
|
v.handle_const_fn_call(e, did, |
|
node_ty) |
|
} |
|
ty::TraitContainer(_) => false, |
|
} |
|
} |
|
_ => false, |
|
}; |
|
if !is_const { |
|
v.add_qualif(ConstQualif::NOT_CONST); |
|
if v.mode != Mode::Var { |
|
fn span_limited_call_error(tcx: &ty::ctxt, |
|
span: Span, s: &str) { |
|
{ |
|
(); |
|
tcx.sess.span_err_with_code(span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&[""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&s,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0015") |
|
}; |
|
} |
|
match v.tcx.sess.opts.unstable_features { |
|
UnstableFeatures::Disallow => { |
|
span_limited_call_error(&v.tcx, e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["function calls in ", |
|
"s are limited to struct and enum constructors"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}))); |
|
v.tcx.sess.span_note(e.span, |
|
"a limited form of compile-time function evaluation is available on a nightly compiler via `const fn`"); |
|
} |
|
_ => { |
|
span_limited_call_error(&v.tcx, e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["function calls in ", |
|
"s are limited to constant functions, struct and enum constructors"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}))); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
hir::ExprMethodCall(..) => { |
|
let method = |
|
v.tcx.tables.borrow().method_map[&method_call]; |
|
let is_const = |
|
match v.tcx.impl_or_trait_item(method.def_id).container() |
|
{ |
|
ty::ImplContainer(_) => |
|
v.handle_const_fn_call(e, method.def_id, node_ty), |
|
ty::TraitContainer(_) => false, |
|
}; |
|
if !is_const { |
|
v.add_qualif(ConstQualif::NOT_CONST); |
|
if v.mode != Mode::Var { |
|
{ |
|
(); |
|
v.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["method calls in ", |
|
"s are limited to constant inherent methods"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0378") |
|
}; |
|
} |
|
} |
|
} |
|
hir::ExprStruct(..) => { |
|
let did = |
|
v.tcx.def_map.borrow().get(&e.id).map(|def| |
|
def.def_id()); |
|
if did == v.tcx.lang_items.unsafe_cell_type() { |
|
v.add_qualif(ConstQualif::MUTABLE_MEM); |
|
} |
|
} |
|
hir::ExprLit(_) | hir::ExprAddrOf(..) => { |
|
v.add_qualif(ConstQualif::NON_ZERO_SIZED); |
|
} |
|
hir::ExprRepeat(..) => { |
|
v.add_qualif(ConstQualif::PREFER_IN_PLACE); |
|
} |
|
hir::ExprClosure(..) => { |
|
if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) { |
|
if !(v.mode == Mode::Var) { |
|
{ |
|
::std::rt::begin_unwind("global closures can\'t capture anything", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/middle/check_const.rs", |
|
774u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
v.add_qualif(ConstQualif::NOT_CONST); |
|
} |
|
} |
|
hir::ExprBlock(_) | hir::ExprIndex(..) | hir::ExprField(..) | |
|
hir::ExprTupField(..) | hir::ExprVec(_) | hir::ExprTup(..) => |
|
{ |
|
} |
|
hir::ExprMatch(..) | hir::ExprIf(..) | hir::ExprWhile(..) | |
|
hir::ExprLoop(..) | hir::ExprBreak(_) | hir::ExprAgain(_) | |
|
hir::ExprRet(_) | hir::ExprRange(..) | hir::ExprAssign(..) | |
|
hir::ExprAssignOp(..) | hir::ExprInlineAsm(_) => { |
|
v.add_qualif(ConstQualif::NOT_CONST); |
|
if v.mode != Mode::Var { |
|
{ |
|
(); |
|
v.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["", |
|
" contains unimplemented expression type"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0019") |
|
}; |
|
} |
|
} |
|
} |
|
} |
|
/// Check the adjustments of an expression |
|
fn check_adjustments<'a, |
|
'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, |
|
e: &hir::Expr) { |
|
match v.tcx.tables.borrow().adjustments.get(&e.id) { |
|
None | Some(&ty::adjustment::AdjustReifyFnPointer) | |
|
Some(&ty::adjustment::AdjustUnsafeFnPointer) => { |
|
} |
|
Some(&ty::adjustment::AdjustDerefRef(ty::adjustment::AutoDerefRef { |
|
autoderefs, .. })) => { |
|
if (0..autoderefs as |
|
u32).any(|autoderef| { |
|
v.tcx.is_overloaded_autoderef(e.id, |
|
autoderef) |
|
}) { |
|
v.add_qualif(ConstQualif::NOT_CONST); |
|
if v.mode != Mode::Var { |
|
{ |
|
(); |
|
v.tcx.sess.span_err_with_code(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["user-defined dereference operators are not allowed in ", |
|
"s"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&v.msg(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0400") |
|
}; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
pub fn check_crate(tcx: &ty::ctxt) { |
|
tcx.map.krate().visit_all_items(&mut CheckCrateVisitor{tcx: tcx, |
|
mode: |
|
Mode::Var, |
|
qualif: |
|
ConstQualif::NOT_CONST, |
|
rvalue_borrows: |
|
NodeMap(),}); |
|
tcx.sess.abort_if_errors(); |
|
} |
|
impl <'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> { |
|
fn consume(&mut self, _consume_id: ast::NodeId, |
|
consume_span: Span, cmt: mc::cmt, |
|
_mode: euv::ConsumeMode) { |
|
let mut cur = &cmt; |
|
loop { |
|
match cur.cat { |
|
Categorization::StaticItem => { |
|
if self.mode != Mode::Var { |
|
{ |
|
(); |
|
self.tcx.sess.span_err_with_code(consume_span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["cannot refer to other statics by value, use the address-of operator or a constant instead"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0394") |
|
}; |
|
} |
|
break ; |
|
} |
|
Categorization::Deref(ref cmt, _, _) | |
|
Categorization::Downcast(ref cmt, _) | |
|
Categorization::Interior(ref cmt, _) => cur = cmt, |
|
Categorization::Rvalue(..) | Categorization::Upvar(..) |
|
| Categorization::Local(..) => break , |
|
} |
|
} |
|
} |
|
fn borrow(&mut self, borrow_id: ast::NodeId, borrow_span: Span, |
|
cmt: mc::cmt<'tcx>, _loan_region: ty::Region, |
|
bk: ty::BorrowKind, loan_cause: euv::LoanCause) { |
|
match loan_cause { |
|
euv::LoanCause::AutoUnsafe => { return; } |
|
_ => { } |
|
} |
|
let mut cur = &cmt; |
|
let mut is_interior = false; |
|
loop { |
|
match cur.cat { |
|
Categorization::Rvalue(..) => { |
|
if loan_cause == euv::MatchDiscriminant { |
|
break ; |
|
} |
|
let mutbl = bk.to_mutbl_lossy(); |
|
if mutbl == hir::MutMutable && |
|
self.mode == Mode::StaticMut { |
|
match cmt.ty.sty { |
|
ty::TyArray(_, _) | ty::TySlice(_) => |
|
break , |
|
_ => { } |
|
} |
|
} |
|
self.record_borrow(borrow_id, mutbl); |
|
break ; |
|
} |
|
Categorization::StaticItem => { |
|
if is_interior && self.mode != Mode::Var { |
|
{ |
|
(); |
|
self.tcx.sess.span_err_with_code(borrow_span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["cannot refer to the interior of another static, use a constant instead"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0494") |
|
}; |
|
} |
|
break ; |
|
} |
|
Categorization::Deref(ref cmt, _, _) | |
|
Categorization::Downcast(ref cmt, _) | |
|
Categorization::Interior(ref cmt, _) => { |
|
is_interior = true; |
|
cur = cmt; |
|
} |
|
Categorization::Upvar(..) | Categorization::Local(..) |
|
=> break , |
|
} |
|
} |
|
} |
|
fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) { } |
|
fn mutate(&mut self, _assignment_id: ast::NodeId, |
|
_assignment_span: Span, _assignee_cmt: mc::cmt, |
|
_mode: euv::MutateMode) { |
|
} |
|
fn matched_pat(&mut self, _: &hir::Pat, _: mc::cmt, |
|
_: euv::MatchMode) { |
|
} |
|
fn consume_pat(&mut self, _consume_pat: &hir::Pat, _cmt: mc::cmt, |
|
_mode: euv::ConsumeMode) { |
|
} |
|
} |
|
} |
|
pub mod check_static_recursion { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
use front::map as ast_map; |
|
use session::Session; |
|
use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefVariant, |
|
DefMap}; |
|
use util::nodemap::NodeMap; |
|
use syntax::{ast}; |
|
use syntax::codemap::Span; |
|
use syntax::feature_gate::{GateIssue, emit_feature_err}; |
|
use rustc_front::intravisit::{self, Visitor}; |
|
use rustc_front::hir; |
|
use std::cell::RefCell; |
|
struct CheckCrateVisitor<'a, 'ast:'a> { |
|
sess: &'a Session, |
|
def_map: &'a DefMap, |
|
ast_map: &'a ast_map::Map<'ast>, |
|
discriminant_map: RefCell<NodeMap<Option<&'ast hir::Expr>>>, |
|
} |
|
impl <'a, 'ast:'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> { |
|
fn visit_item(&mut self, it: &'ast hir::Item) { |
|
match it.node { |
|
hir::ItemStatic(..) | hir::ItemConst(..) => { |
|
let mut recursion_visitor = |
|
CheckItemRecursionVisitor::new(self, &it.span); |
|
recursion_visitor.visit_item(it); |
|
} |
|
hir::ItemEnum(ref enum_def, ref generics) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&enum_def.variants) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(variant) |
|
=> { |
|
match variant.node.disr_expr { |
|
Some(_) => { |
|
let mut recursion_visitor = |
|
CheckItemRecursionVisitor::new(self, |
|
&variant.span); |
|
recursion_visitor.populate_enum_discriminants(enum_def); |
|
recursion_visitor.visit_variant(variant, |
|
generics, |
|
it.id); |
|
} |
|
_ => (), |
|
} |
|
} |
|
::std::option::Option::None => |
|
break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
_ => { } |
|
} |
|
intravisit::walk_item(self, it) |
|
} |
|
fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) { |
|
match ti.node { |
|
hir::ConstTraitItem(_, ref default) => { |
|
match *default { |
|
Some(_) => { |
|
let mut recursion_visitor = |
|
CheckItemRecursionVisitor::new(self, |
|
&ti.span); |
|
recursion_visitor.visit_trait_item(ti); |
|
} |
|
_ => (), |
|
} |
|
} |
|
_ => { } |
|
} |
|
intravisit::walk_trait_item(self, ti) |
|
} |
|
fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) { |
|
match ii.node { |
|
hir::ImplItemKind::Const(..) => { |
|
let mut recursion_visitor = |
|
CheckItemRecursionVisitor::new(self, &ii.span); |
|
recursion_visitor.visit_impl_item(ii); |
|
} |
|
_ => { } |
|
} |
|
intravisit::walk_impl_item(self, ii) |
|
} |
|
} |
|
pub fn check_crate<'ast>(sess: &Session, krate: &'ast hir::Crate, |
|
def_map: &DefMap, |
|
ast_map: &ast_map::Map<'ast>) { |
|
let mut visitor = |
|
CheckCrateVisitor{sess: sess, |
|
def_map: def_map, |
|
ast_map: ast_map, |
|
discriminant_map: RefCell::new(NodeMap()),}; |
|
krate.visit_all_items(&mut visitor); |
|
sess.abort_if_errors(); |
|
} |
|
struct CheckItemRecursionVisitor<'a, 'ast:'a> { |
|
root_span: &'a Span, |
|
sess: &'a Session, |
|
ast_map: &'a ast_map::Map<'ast>, |
|
def_map: &'a DefMap, |
|
discriminant_map: &'a RefCell<NodeMap<Option<&'ast hir::Expr>>>, |
|
idstack: Vec<ast::NodeId>, |
|
} |
|
impl <'a, 'ast:'a> CheckItemRecursionVisitor<'a, 'ast> { |
|
fn new(v: &'a CheckCrateVisitor<'a, 'ast>, span: &'a Span) |
|
-> CheckItemRecursionVisitor<'a, 'ast> { |
|
CheckItemRecursionVisitor{root_span: span, |
|
sess: v.sess, |
|
ast_map: v.ast_map, |
|
def_map: v.def_map, |
|
discriminant_map: |
|
&v.discriminant_map, |
|
idstack: Vec::new(),} |
|
} |
|
fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F) where |
|
F: Fn(&mut Self) { |
|
if self.idstack.iter().any(|&x| x == id) { |
|
let any_static = |
|
self.idstack.iter().any(|&x| { |
|
match self.ast_map.get(x) { |
|
ast_map::NodeItem(item) => |
|
{ |
|
match item.node { |
|
hir::ItemStatic(..) |
|
=> { |
|
true |
|
} |
|
_ => { false } |
|
} |
|
} |
|
_ => { false } |
|
} }); |
|
if any_static { |
|
if !self.sess.features.borrow().static_recursion { |
|
emit_feature_err(&self.sess.parse_sess.span_diagnostic, |
|
"static_recursion", |
|
*self.root_span, |
|
GateIssue::Language, |
|
"recursive static"); |
|
} |
|
} else { |
|
{ |
|
(); |
|
self.sess.span_err_with_code(*self.root_span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["recursive constant"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0265") |
|
}; |
|
} |
|
return; |
|
} |
|
self.idstack.push(id); |
|
f(self); |
|
self.idstack.pop(); |
|
} |
|
fn populate_enum_discriminants(&self, |
|
enum_definition: |
|
&'ast hir::EnumDef) { |
|
let mut discriminant_map = self.discriminant_map.borrow_mut(); |
|
match enum_definition.variants.first() { |
|
None => { return; } |
|
Some(variant) if |
|
discriminant_map.contains_key(&variant.node.data.id()) => |
|
{ |
|
return; |
|
} |
|
_ => { } |
|
} |
|
let mut variant_stack: Vec<ast::NodeId> = Vec::new(); |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(enum_definition.variants.iter().rev()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(variant) => { |
|
variant_stack.push(variant.node.data.id()); |
|
match variant.node.disr_expr { |
|
Some(ref expr) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&variant_stack) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(id) |
|
=> { |
|
discriminant_map.insert(*id, |
|
Some(expr)); |
|
} |
|
::std::option::Option::None |
|
=> break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
variant_stack.clear() |
|
} |
|
_ => (), |
|
} |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&variant_stack) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(id) => { |
|
discriminant_map.insert(*id, None); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
} |
|
impl <'a, 'ast:'a> Visitor<'ast> for |
|
CheckItemRecursionVisitor<'a, 'ast> { |
|
fn visit_item(&mut self, it: &'ast hir::Item) { |
|
self.with_item_id_pushed(it.id, |
|
|v| intravisit::walk_item(v, it)); |
|
} |
|
fn visit_enum_def(&mut self, enum_definition: &'ast hir::EnumDef, |
|
generics: &'ast hir::Generics, |
|
item_id: ast::NodeId, _: Span) { |
|
self.populate_enum_discriminants(enum_definition); |
|
intravisit::walk_enum_def(self, enum_definition, generics, |
|
item_id); |
|
} |
|
fn visit_variant(&mut self, variant: &'ast hir::Variant, |
|
_: &'ast hir::Generics, _: ast::NodeId) { |
|
let variant_id = variant.node.data.id(); |
|
let maybe_expr; |
|
match self.discriminant_map.borrow().get(&variant_id) { |
|
Some(get_expr) => { maybe_expr = (*get_expr).clone(); } |
|
_ => { |
|
self.sess.span_bug(variant.span, |
|
"`check_static_recursion` attempted to visit variant with unknown discriminant") |
|
} |
|
} |
|
match maybe_expr { |
|
Some(expr) => { |
|
self.with_item_id_pushed(expr.id, |
|
|v| |
|
intravisit::walk_expr(v, |
|
expr)); |
|
} |
|
_ => (), |
|
} |
|
} |
|
fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) { |
|
self.with_item_id_pushed(ti.id, |
|
|v| |
|
intravisit::walk_trait_item(v, |
|
ti)); |
|
} |
|
fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) { |
|
self.with_item_id_pushed(ii.id, |
|
|v| |
|
intravisit::walk_impl_item(v, |
|
ii)); |
|
} |
|
fn visit_expr(&mut self, e: &'ast hir::Expr) { |
|
match e.node { |
|
hir::ExprPath(..) => { |
|
match self.def_map.get(&e.id).map(|d| d.base_def) { |
|
Some(DefStatic(def_id, _)) | |
|
Some(DefAssociatedConst(def_id)) | |
|
Some(DefConst(def_id)) => { |
|
match self.ast_map.as_local_node_id(def_id) { |
|
Some(node_id) => { |
|
match self.ast_map.get(node_id) { |
|
ast_map::NodeItem(item) => |
|
self.visit_item(item), |
|
ast_map::NodeTraitItem(item) => |
|
self.visit_trait_item(item), |
|
ast_map::NodeImplItem(item) => |
|
self.visit_impl_item(item), |
|
ast_map::NodeForeignItem(_) => { } |
|
_ => { |
|
self.sess.span_bug(e.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["expected item, found "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&self.ast_map.node_to_string(node_id),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
}))); |
|
} |
|
} |
|
} |
|
_ => (), |
|
} |
|
} |
|
Some(DefVariant(enum_id, variant_id, false)) => { |
|
match self.ast_map.as_local_node_id(enum_id) { |
|
Some(enum_node_id) => { |
|
match self.ast_map.expect_item(enum_node_id).node |
|
{ |
|
hir::ItemEnum(ref enum_def, |
|
ref generics) => { |
|
self.populate_enum_discriminants(enum_def); |
|
let enum_id = |
|
self.ast_map.as_local_node_id(enum_id).unwrap(); |
|
let variant_id = |
|
self.ast_map.as_local_node_id(variant_id).unwrap(); |
|
let variant = |
|
self.ast_map.expect_variant(variant_id); |
|
self.visit_variant(variant, |
|
generics, |
|
enum_id); |
|
} |
|
_ => { |
|
self.sess.span_bug(e.span, |
|
"`check_static_recursion` found non-enum in DefVariant"); |
|
} |
|
} |
|
} |
|
_ => (), |
|
} |
|
} |
|
_ => (), |
|
} |
|
} |
|
_ => (), |
|
} |
|
intravisit::walk_expr(self, e); |
|
} |
|
} |
|
} |
|
pub mod check_loop { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
use self::Context::*; |
|
use session::Session; |
|
use syntax::codemap::Span; |
|
use rustc_front::intravisit::{self, Visitor}; |
|
use rustc_front::hir; |
|
enum Context { Normal, Loop, Closure, } |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for Context { |
|
#[inline] |
|
fn eq(&self, __arg_0: &Context) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&Context::Normal, &Context::Normal) => true, |
|
(&Context::Loop, &Context::Loop) => true, |
|
(&Context::Closure, &Context::Closure) => true, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &Context) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&Context::Normal, &Context::Normal) => false, |
|
(&Context::Loop, &Context::Loop) => false, |
|
(&Context::Closure, &Context::Closure) => false, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for Context { } |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for Context { |
|
#[inline] |
|
fn clone(&self) -> Context { |
|
match (&*self,) { |
|
(&Context::Normal,) => Context::Normal, |
|
(&Context::Loop,) => Context::Loop, |
|
(&Context::Closure,) => Context::Closure, |
|
} |
|
} |
|
} |
|
struct CheckLoopVisitor<'a> { |
|
sess: &'a Session, |
|
cx: Context, |
|
} |
|
#[automatically_derived] |
|
impl <'a> ::std::clone::Clone for CheckLoopVisitor<'a> { |
|
#[inline] |
|
fn clone(&self) -> CheckLoopVisitor<'a> { |
|
match *self { |
|
CheckLoopVisitor { |
|
sess: ref __self_0_0, cx: ref __self_0_1 } => |
|
CheckLoopVisitor{sess: |
|
::std::clone::Clone::clone(&(*__self_0_0)), |
|
cx: |
|
::std::clone::Clone::clone(&(*__self_0_1)),}, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl <'a> ::std::marker::Copy for CheckLoopVisitor<'a> { } |
|
pub fn check_crate(sess: &Session, krate: &hir::Crate) { |
|
krate.visit_all_items(&mut CheckLoopVisitor{sess: sess, |
|
cx: Normal,}); |
|
} |
|
impl <'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { |
|
fn visit_item(&mut self, i: &hir::Item) { |
|
self.with_context(Normal, |v| intravisit::walk_item(v, i)); |
|
} |
|
fn visit_expr(&mut self, e: &hir::Expr) { |
|
match e.node { |
|
hir::ExprWhile(ref e, ref b, _) => { |
|
self.visit_expr(&**e); |
|
self.with_context(Loop, |v| v.visit_block(&**b)); |
|
} |
|
hir::ExprLoop(ref b, _) => { |
|
self.with_context(Loop, |v| v.visit_block(&**b)); |
|
} |
|
hir::ExprClosure(_, _, ref b) => { |
|
self.with_context(Closure, |v| v.visit_block(&**b)); |
|
} |
|
hir::ExprBreak(_) => self.require_loop("break", e.span), |
|
hir::ExprAgain(_) => |
|
self.require_loop("continue", e.span), |
|
_ => intravisit::walk_expr(self, e), |
|
} |
|
} |
|
} |
|
impl <'a> CheckLoopVisitor<'a> { |
|
fn with_context<F>(&mut self, cx: Context, f: F) where |
|
F: FnOnce(&mut CheckLoopVisitor<'a>) { |
|
let old_cx = self.cx; |
|
self.cx = cx; |
|
f(self); |
|
self.cx = old_cx; |
|
} |
|
fn require_loop(&self, name: &str, span: Span) { |
|
match self.cx { |
|
Loop => { } |
|
Closure => { |
|
{ |
|
(); |
|
self.sess.span_err_with_code(span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["`", |
|
"` inside of a closure"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&name,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0267") |
|
}; |
|
} |
|
Normal => { |
|
{ |
|
(); |
|
self.sess.span_err_with_code(span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["`", |
|
"` outside of loop"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&name,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0268") |
|
}; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
pub mod check_match { |
|
#[prelude_import] |
|
use std::prelude::v1::*; |
|
pub use self::Constructor::*; |
|
use self::Usefulness::*; |
|
use self::WitnessPreference::*; |
|
use middle::const_eval::{compare_const_vals, ConstVal}; |
|
use middle::const_eval::{eval_const_expr, eval_const_expr_partial}; |
|
use middle::const_eval::{const_expr_to_pat, lookup_const_by_id}; |
|
use middle::const_eval::EvalHint::ExprTypeChecked; |
|
use middle::def::*; |
|
use middle::def_id::{DefId}; |
|
use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, |
|
Init}; |
|
use middle::expr_use_visitor::{JustWrite, LoanCause, MutateMode}; |
|
use middle::expr_use_visitor::WriteAndRead; |
|
use middle::expr_use_visitor as euv; |
|
use middle::infer; |
|
use middle::mem_categorization::{cmt}; |
|
use middle::pat_util::*; |
|
use middle::ty::*; |
|
use middle::ty; |
|
use std::cmp::Ordering; |
|
use std::fmt; |
|
use std::iter::{FromIterator, IntoIterator, repeat}; |
|
use rustc_front::hir; |
|
use rustc_front::hir::Pat; |
|
use rustc_front::intravisit::{self, Visitor, FnKind}; |
|
use rustc_front::util as front_util; |
|
use rustc_back::slice; |
|
use syntax::ast::{self, DUMMY_NODE_ID, NodeId}; |
|
use syntax::ast_util; |
|
use syntax::codemap::{Span, Spanned, DUMMY_SP}; |
|
use rustc_front::fold::{Folder, noop_fold_pat}; |
|
use rustc_front::print::pprust::pat_to_string; |
|
use syntax::ptr::P; |
|
use util::nodemap::FnvHashMap; |
|
pub const DUMMY_WILD_PAT: &'static Pat = |
|
&Pat{id: DUMMY_NODE_ID, node: hir::PatWild, span: DUMMY_SP,}; |
|
struct Matrix<'a>(Vec<Vec<&'a Pat>>); |
|
/// Pretty-printer for matrices of patterns, example: |
|
/// ++++++++++++++++++++++++++ |
|
/// + _ + [] + |
|
/// ++++++++++++++++++++++++++ |
|
/// + true + [First] + |
|
/// ++++++++++++++++++++++++++ |
|
/// + true + [Second(true)] + |
|
/// ++++++++++++++++++++++++++ |
|
/// + false + [_] + |
|
/// ++++++++++++++++++++++++++ |
|
/// + _ + [_, _, ..tail] + |
|
/// ++++++++++++++++++++++++++ |
|
impl <'a> fmt::Debug for Matrix<'a> { |
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
match f.write_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["\n"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () { |
|
() => [], |
|
})) { |
|
::std::result::Result::Ok(val) => val, |
|
::std::result::Result::Err(err) => { |
|
return ::std::result::Result::Err(::std::convert::From::from(err)) |
|
} |
|
}; |
|
let &Matrix(ref m) = self; |
|
let pretty_printed_matrix: Vec<Vec<String>> = |
|
m.iter().map(|row| { |
|
row.iter().map(|&pat| |
|
pat_to_string(&*pat)).collect::<Vec<String>>() |
|
}).collect(); |
|
let column_count = |
|
m.iter().map(|row| row.len()).max().unwrap_or(0); |
|
if !m.iter().all(|row| row.len() == column_count) { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: m.iter().all(|row| row.len() == column_count)", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, u32) |
|
= |
|
("src/librustc/middle/check_match.rs", |
|
80u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
let column_widths: Vec<usize> = |
|
(0..column_count).map(|col| { |
|
pretty_printed_matrix.iter().map(|row| |
|
row[col].len()).max().unwrap_or(0) |
|
}).collect(); |
|
let total_width = |
|
column_widths.iter().cloned().sum::<usize>() + |
|
column_count * 3 + 1; |
|
let br = repeat('+').take(total_width).collect::<String>(); |
|
match f.write_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["", |
|
"\n"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&br,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})) { |
|
::std::result::Result::Ok(val) => val, |
|
::std::result::Result::Err(err) => { |
|
return ::std::result::Result::Err(::std::convert::From::from(err)) |
|
} |
|
}; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(pretty_printed_matrix) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(row) => { |
|
match f.write_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["+"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
{ |
|
::std::result::Result::Ok(val) => |
|
val, |
|
::std::result::Result::Err(err) => |
|
{ |
|
return ::std::result::Result::Err(::std::convert::From::from(err)) |
|
} |
|
}; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(row.into_iter().enumerate()) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some((column, |
|
pat_str)) |
|
=> { |
|
match f.write_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&[" "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
{ |
|
::std::result::Result::Ok(val) |
|
=> val, |
|
::std::result::Result::Err(err) |
|
=> { |
|
return ::std::result::Result::Err(::std::convert::From::from(err)) |
|
} |
|
}; |
|
match f.write_fmt(::std::fmt::Arguments::new_v1_formatted({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&[""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&pat_str, |
|
&column_widths[column]) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::from_usize(__arg1)], |
|
}, |
|
{ |
|
static __STATIC_FMTARGS: |
|
&'static [::std::fmt::rt::v1::Argument] |
|
= |
|
&[::std::fmt::rt::v1::Argument{position: |
|
::std::fmt::rt::v1::Position::Next, |
|
format: |
|
::std::fmt::rt::v1::FormatSpec{fill: |
|
' ', |
|
align: |
|
::std::fmt::rt::v1::Alignment::Unknown, |
|
flags: |
|
0u32, |
|
precision: |
|
::std::fmt::rt::v1::Count::Implied, |
|
width: |
|
::std::fmt::rt::v1::Count::Param(1usize),},}]; |
|
__STATIC_FMTARGS |
|
})) |
|
{ |
|
::std::result::Result::Ok(val) |
|
=> val, |
|
::std::result::Result::Err(err) |
|
=> { |
|
return ::std::result::Result::Err(::std::convert::From::from(err)) |
|
} |
|
}; |
|
match f.write_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&[" +"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
{ |
|
::std::result::Result::Ok(val) |
|
=> val, |
|
::std::result::Result::Err(err) |
|
=> { |
|
return ::std::result::Result::Err(::std::convert::From::from(err)) |
|
} |
|
}; |
|
} |
|
::std::option::Option::None |
|
=> break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
match f.write_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["\n"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})) |
|
{ |
|
::std::result::Result::Ok(val) => |
|
val, |
|
::std::result::Result::Err(err) => |
|
{ |
|
return ::std::result::Result::Err(::std::convert::From::from(err)) |
|
} |
|
}; |
|
match f.write_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["", |
|
"\n"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&br,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})) |
|
{ |
|
::std::result::Result::Ok(val) => |
|
val, |
|
::std::result::Result::Err(err) => |
|
{ |
|
return ::std::result::Result::Err(::std::convert::From::from(err)) |
|
} |
|
}; |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
Ok(()) |
|
} |
|
} |
|
impl <'a> FromIterator<Vec<&'a Pat>> for Matrix<'a> { |
|
fn from_iter<T: IntoIterator<Item = Vec<&'a Pat>>>(iter: T) |
|
-> Matrix<'a> { |
|
Matrix(iter.into_iter().collect()) |
|
} |
|
} |
|
pub struct MatchCheckCtxt<'a, 'tcx:'a> { |
|
pub tcx: &'a ty::ctxt<'tcx>, |
|
pub param_env: ParameterEnvironment<'a, 'tcx>, |
|
} |
|
pub enum Constructor { |
|
|
|
/// The constructor of all patterns that don't vary by constructor, |
|
/// e.g. struct patterns and fixed-length arrays. |
|
Single, |
|
|
|
/// Enum variants. |
|
Variant(DefId), |
|
|
|
/// Literal values. |
|
ConstantValue(ConstVal), |
|
|
|
/// Ranges of literal values (2..5). |
|
ConstantRange(ConstVal, ConstVal), |
|
|
|
/// Array patterns of length n. |
|
Slice(usize), |
|
|
|
/// Array patterns with a subslice. |
|
SliceWithSubslice(usize, usize), |
|
} |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for Constructor { |
|
#[inline] |
|
fn eq(&self, __arg_0: &Constructor) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&Constructor::Single, &Constructor::Single) => |
|
true, |
|
(&Constructor::Variant(ref __self_0), |
|
&Constructor::Variant(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&Constructor::ConstantValue(ref __self_0), |
|
&Constructor::ConstantValue(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&Constructor::ConstantRange(ref __self_0, |
|
ref __self_1), |
|
&Constructor::ConstantRange(ref __arg_1_0, |
|
ref __arg_1_1)) => |
|
true && (*__self_0) == (*__arg_1_0) && |
|
(*__self_1) == (*__arg_1_1), |
|
(&Constructor::Slice(ref __self_0), |
|
&Constructor::Slice(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&Constructor::SliceWithSubslice(ref __self_0, |
|
ref __self_1), |
|
&Constructor::SliceWithSubslice(ref __arg_1_0, |
|
ref __arg_1_1)) |
|
=> |
|
true && (*__self_0) == (*__arg_1_0) && |
|
(*__self_1) == (*__arg_1_1), |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &Constructor) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&Constructor::Single, &Constructor::Single) => |
|
false, |
|
(&Constructor::Variant(ref __self_0), |
|
&Constructor::Variant(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&Constructor::ConstantValue(ref __self_0), |
|
&Constructor::ConstantValue(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&Constructor::ConstantRange(ref __self_0, |
|
ref __self_1), |
|
&Constructor::ConstantRange(ref __arg_1_0, |
|
ref __arg_1_1)) => |
|
false || (*__self_0) != (*__arg_1_0) || |
|
(*__self_1) != (*__arg_1_1), |
|
(&Constructor::Slice(ref __self_0), |
|
&Constructor::Slice(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&Constructor::SliceWithSubslice(ref __self_0, |
|
ref __self_1), |
|
&Constructor::SliceWithSubslice(ref __arg_1_0, |
|
ref __arg_1_1)) |
|
=> |
|
false || (*__self_0) != (*__arg_1_0) || |
|
(*__self_1) != (*__arg_1_1), |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for Constructor { |
|
#[inline] |
|
fn clone(&self) -> Constructor { |
|
match (&*self,) { |
|
(&Constructor::Single,) => Constructor::Single, |
|
(&Constructor::Variant(ref __self_0),) => |
|
Constructor::Variant(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Constructor::ConstantValue(ref __self_0),) => |
|
Constructor::ConstantValue(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Constructor::ConstantRange(ref __self_0, ref __self_1),) |
|
=> |
|
Constructor::ConstantRange(::std::clone::Clone::clone(&(*__self_0)), |
|
::std::clone::Clone::clone(&(*__self_1))), |
|
(&Constructor::Slice(ref __self_0),) => |
|
Constructor::Slice(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Constructor::SliceWithSubslice(ref __self_0, |
|
ref __self_1),) => |
|
Constructor::SliceWithSubslice(::std::clone::Clone::clone(&(*__self_0)), |
|
::std::clone::Clone::clone(&(*__self_1))), |
|
} |
|
} |
|
} |
|
enum Usefulness { Useful, UsefulWithWitness(Vec<P<Pat>>), NotUseful, } |
|
#[automatically_derived] |
|
impl ::std::cmp::PartialEq for Usefulness { |
|
#[inline] |
|
fn eq(&self, __arg_0: &Usefulness) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&Usefulness::Useful, &Usefulness::Useful) => |
|
true, |
|
(&Usefulness::UsefulWithWitness(ref __self_0), |
|
&Usefulness::UsefulWithWitness(ref __arg_1_0)) => |
|
true && (*__self_0) == (*__arg_1_0), |
|
(&Usefulness::NotUseful, &Usefulness::NotUseful) |
|
=> true, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { false } |
|
} |
|
} |
|
#[inline] |
|
fn ne(&self, __arg_0: &Usefulness) -> bool { |
|
{ |
|
let __self_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*self) |
|
} as i32; |
|
let __arg_1_vi = |
|
unsafe { |
|
::std::intrinsics::discriminant_value(&*__arg_0) |
|
} as i32; |
|
if true && __self_vi == __arg_1_vi { |
|
match (&*self, &*__arg_0) { |
|
(&Usefulness::Useful, &Usefulness::Useful) => |
|
false, |
|
(&Usefulness::UsefulWithWitness(ref __self_0), |
|
&Usefulness::UsefulWithWitness(ref __arg_1_0)) => |
|
false || (*__self_0) != (*__arg_1_0), |
|
(&Usefulness::NotUseful, &Usefulness::NotUseful) |
|
=> false, |
|
_ => unsafe { ::std::intrinsics::unreachable() } |
|
} |
|
} else { true } |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for Usefulness { |
|
#[inline] |
|
fn clone(&self) -> Usefulness { |
|
match (&*self,) { |
|
(&Usefulness::Useful,) => Usefulness::Useful, |
|
(&Usefulness::UsefulWithWitness(ref __self_0),) => |
|
Usefulness::UsefulWithWitness(::std::clone::Clone::clone(&(*__self_0))), |
|
(&Usefulness::NotUseful,) => Usefulness::NotUseful, |
|
} |
|
} |
|
} |
|
enum WitnessPreference { ConstructWitness, LeaveOutWitness, } |
|
#[automatically_derived] |
|
impl ::std::clone::Clone for WitnessPreference { |
|
#[inline] |
|
fn clone(&self) -> WitnessPreference { |
|
match (&*self,) { |
|
(&WitnessPreference::ConstructWitness,) => |
|
WitnessPreference::ConstructWitness, |
|
(&WitnessPreference::LeaveOutWitness,) => |
|
WitnessPreference::LeaveOutWitness, |
|
} |
|
} |
|
} |
|
#[automatically_derived] |
|
impl ::std::marker::Copy for WitnessPreference { } |
|
impl <'a, 'tcx, 'v> Visitor<'v> for MatchCheckCtxt<'a, 'tcx> { |
|
fn visit_expr(&mut self, ex: &hir::Expr) { check_expr(self, ex); } |
|
fn visit_local(&mut self, l: &hir::Local) { |
|
check_local(self, l); |
|
} |
|
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, |
|
b: &'v hir::Block, s: Span, n: NodeId) { |
|
check_fn(self, fk, fd, b, s, n); |
|
} |
|
} |
|
pub fn check_crate(tcx: &ty::ctxt) { |
|
tcx.map.krate().visit_all_items(&mut MatchCheckCtxt{tcx: tcx, |
|
param_env: |
|
tcx.empty_parameter_environment(),}); |
|
tcx.sess.abort_if_errors(); |
|
} |
|
fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) { |
|
intravisit::walk_expr(cx, ex); |
|
match ex.node { |
|
hir::ExprMatch(ref scrut, ref arms, source) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(arms) { |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(arm) => { |
|
check_legality_of_move_bindings(cx, |
|
arm.guard.is_some(), |
|
&arm.pats); |
|
match arm.guard { |
|
Some(ref guard) => |
|
check_for_mutation_in_guard(cx, |
|
&**guard), |
|
None => { } |
|
} |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
let mut static_inliner = StaticInliner::new(cx.tcx, None); |
|
let inlined_arms = |
|
arms.iter().map(|arm| { |
|
(arm.pats.iter().map(|pat| { |
|
static_inliner.fold_pat((*pat).clone()) |
|
}).collect(), |
|
arm.guard.as_ref().map(|e| &**e)) |
|
}).collect::<Vec<(Vec<P<Pat>>, |
|
Option<&hir::Expr>)>>(); |
|
if static_inliner.failed { return; } |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(inlined_arms.iter().flat_map(|&(ref pats, |
|
_)| |
|
pats)) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(pat) => { |
|
check_legality_of_bindings_in_at_patterns(cx, |
|
&**pat); |
|
check_for_static_nan(cx, &**pat); |
|
check_for_bindings_named_the_same_as_variants(cx, |
|
&**pat); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
check_arms(cx, &inlined_arms[..], source); |
|
let pat_ty = cx.tcx.node_id_to_type(scrut.id); |
|
if inlined_arms.is_empty() { |
|
if !pat_ty.is_empty(cx.tcx) { |
|
{ |
|
(); |
|
cx.tcx.sess.span_err_with_code(ex.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["non-exhaustive patterns: type ", |
|
" is non-empty"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&pat_ty,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0002") |
|
}; |
|
{ |
|
(cx.tcx.sess).span_help(ex.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["Please ensure that all possible cases are being handled; possibly adding wildcards or more match arms."]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
}))) |
|
}; |
|
} |
|
return; |
|
} |
|
let matrix: Matrix = |
|
inlined_arms.iter().filter(|&&(_, guard)| |
|
guard.is_none()).flat_map(|arm| |
|
&arm.0).map(|pat| |
|
<[_]>::into_vec(::std::boxed::Box::new([&**pat]))).collect(); |
|
check_exhaustive(cx, ex.span, &matrix, source); |
|
} |
|
_ => (), |
|
} |
|
} |
|
fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, |
|
pat: &Pat) { |
|
front_util::walk_pat(pat, |p| { |
|
match p.node { |
|
hir::PatIdent(hir::BindByValue(hir::MutImmutable), |
|
ident, None) => { |
|
let pat_ty = cx.tcx.pat_ty(p); |
|
match pat_ty.sty { |
|
ty::TyEnum(edef, _) => { |
|
let def = |
|
cx.tcx.def_map.borrow().get(&p.id).map(|d| |
|
d.full_def()); |
|
match def { |
|
Some(DefLocal(..)) => { |
|
if edef.variants.iter().any(|variant| |
|
variant.name |
|
== |
|
ident.node.name |
|
&& |
|
variant.kind() |
|
== |
|
VariantKind::Unit) |
|
{ |
|
{ |
|
(); |
|
cx.tcx.sess.span_warn_with_code(p.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["pattern binding `", |
|
"` is named the same as one of the variants of the type `", |
|
"`"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&ident.node, |
|
&pat_ty) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0170") |
|
}; |
|
{ |
|
(cx.tcx.sess).fileline_help(p.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["if you meant to match on a variant, consider making the path in the pattern qualified: `", |
|
"::", |
|
"`"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&pat_ty, |
|
&ident.node) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
}))) |
|
}; |
|
} |
|
} |
|
_ => (), |
|
} |
|
} |
|
_ => (), |
|
} |
|
} |
|
_ => (), |
|
} true }); |
|
} |
|
fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) { |
|
front_util::walk_pat(pat, |p| { |
|
match p.node { |
|
hir::PatLit(ref expr) => { |
|
match eval_const_expr_partial(cx.tcx, |
|
&**expr, |
|
ExprTypeChecked, |
|
None) { |
|
Ok(ConstVal::Float(f)) if |
|
f.is_nan() => { |
|
{ |
|
(); |
|
cx.tcx.sess.span_warn_with_code(p.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["unmatchable NaN in pattern, use the is_nan method in a guard instead"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0003") |
|
}; |
|
} |
|
Ok(_) => { } |
|
Err(err) => { |
|
{ |
|
(); |
|
cx.tcx.sess.span_err_with_code(err.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["constant evaluation error: "]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&err.description(),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0471") |
|
}; |
|
if !p.span.contains(err.span) |
|
{ |
|
cx.tcx.sess.span_note(p.span, |
|
"in pattern here") |
|
} |
|
} |
|
} |
|
} |
|
_ => (), |
|
} true }); |
|
} |
|
fn check_arms(cx: &MatchCheckCtxt, |
|
arms: &[(Vec<P<Pat>>, Option<&hir::Expr>)], |
|
source: hir::MatchSource) { |
|
let mut seen = |
|
Matrix(<[_]>::into_vec(::std::boxed::Box::new([]))); |
|
let mut printed_if_let_err = false; |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(arms) { |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(&(ref pats, |
|
guard)) => { |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(pats) |
|
{ |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) |
|
{ |
|
::std::option::Option::Some(pat) |
|
=> { |
|
let v = |
|
<[_]>::into_vec(::std::boxed::Box::new([&**pat])); |
|
match is_useful(cx, |
|
&seen, |
|
&v[..], |
|
LeaveOutWitness) |
|
{ |
|
NotUseful => { |
|
match source |
|
{ |
|
hir::MatchSource::IfLetDesugar { |
|
.. } |
|
=> { |
|
if printed_if_let_err |
|
{ |
|
} else { |
|
let &(ref first_arm_pats, |
|
_) = |
|
&arms[0]; |
|
let first_pat = |
|
&first_arm_pats[0]; |
|
let span = |
|
first_pat.span; |
|
{ |
|
(); |
|
cx.tcx.sess.span_err_with_code(span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["irrefutable if-let pattern"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0162") |
|
}; |
|
printed_if_let_err |
|
= |
|
true; |
|
} |
|
} |
|
hir::MatchSource::WhileLetDesugar |
|
=> { |
|
let &(ref first_arm_pats, |
|
_) = |
|
&arms[0]; |
|
let first_pat = |
|
&first_arm_pats[0]; |
|
let span = |
|
first_pat.span; |
|
{ |
|
(); |
|
cx.tcx.sess.span_err_with_code(span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["irrefutable while-let pattern"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0165") |
|
}; |
|
} |
|
hir::MatchSource::ForLoopDesugar |
|
=> { |
|
cx.tcx.sess.span_bug(pat.span, |
|
"unreachable for-loop pattern") |
|
} |
|
hir::MatchSource::Normal |
|
=> { |
|
{ |
|
(); |
|
cx.tcx.sess.span_err_with_code(pat.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["unreachable pattern"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0001") |
|
} |
|
} |
|
} |
|
} |
|
Useful => (), |
|
UsefulWithWitness(_) |
|
=> { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/middle/check_match.rs", |
|
347u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
if guard.is_none() |
|
{ |
|
let Matrix(mut rows) = |
|
seen; |
|
rows.push(v); |
|
seen = |
|
Matrix(rows); |
|
} |
|
} |
|
::std::option::Option::None |
|
=> break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
fn raw_pat<'a>(p: &'a Pat) -> &'a Pat { |
|
match p.node { |
|
hir::PatIdent(_, _, Some(ref s)) => raw_pat(&**s), |
|
_ => p, |
|
} |
|
} |
|
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, |
|
source: hir::MatchSource) { |
|
match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) { |
|
UsefulWithWitness(pats) => { |
|
let witness = |
|
match &pats[..] { |
|
[ref witness] => &**witness, |
|
[] => DUMMY_WILD_PAT, |
|
_ => { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/middle/check_match.rs", |
|
371u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
}; |
|
match source { |
|
hir::MatchSource::ForLoopDesugar => { |
|
let witness = |
|
match witness.node { |
|
hir::PatEnum(_, Some(ref pats)) => |
|
match &pats[..] { |
|
[ref pat] => &**pat, |
|
_ => { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/middle/check_match.rs", |
|
379u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
}, |
|
_ => { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/middle/check_match.rs", |
|
381u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
}; |
|
{ |
|
(); |
|
cx.tcx.sess.span_err_with_code(sp, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["refutable pattern in `for` loop binding: `", |
|
"` not covered"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&pat_to_string(witness),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0297") |
|
}; |
|
} |
|
_ => { |
|
{ |
|
(); |
|
cx.tcx.sess.span_err_with_code(sp, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["non-exhaustive patterns: `", |
|
"` not covered"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&pat_to_string(witness),) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0004") |
|
}; |
|
} |
|
} |
|
} |
|
NotUseful => { } |
|
_ => { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, u32) |
|
= |
|
("src/librustc/middle/check_match.rs", |
|
400u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> { |
|
let node = |
|
match value { |
|
&ConstVal::Bool(b) => ast::LitBool(b), |
|
_ => { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/middle/check_match.rs", |
|
407u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
}; |
|
P(hir::Expr{id: 0, |
|
node: |
|
hir::ExprLit(P(Spanned{node: node, |
|
span: DUMMY_SP,})), |
|
span: DUMMY_SP, |
|
attrs: None,}) |
|
} |
|
pub struct StaticInliner<'a, 'tcx:'a> { |
|
pub tcx: &'a ty::ctxt<'tcx>, |
|
pub failed: bool, |
|
pub renaming_map: Option<&'a mut FnvHashMap<(NodeId, Span), |
|
NodeId>>, |
|
} |
|
impl <'a, 'tcx> StaticInliner<'a, 'tcx> { |
|
pub fn new<'b>(tcx: &'b ty::ctxt<'tcx>, |
|
renaming_map: |
|
Option<&'b mut FnvHashMap<(NodeId, Span), |
|
NodeId>>) |
|
-> StaticInliner<'b, 'tcx> { |
|
StaticInliner{tcx: tcx, |
|
failed: false, |
|
renaming_map: renaming_map,} |
|
} |
|
} |
|
struct RenamingRecorder<'map> { |
|
substituted_node_id: NodeId, |
|
origin_span: Span, |
|
renaming_map: &'map mut FnvHashMap<(NodeId, Span), NodeId>, |
|
} |
|
impl <'map> ast_util::IdVisitingOperation for RenamingRecorder<'map> { |
|
fn visit_id(&mut self, node_id: NodeId) { |
|
let key = (node_id, self.origin_span); |
|
self.renaming_map.insert(key, self.substituted_node_id); |
|
} |
|
} |
|
impl <'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { |
|
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> { |
|
return match pat.node { |
|
hir::PatIdent(..) | hir::PatEnum(..) | |
|
hir::PatQPath(..) => { |
|
let def = |
|
self.tcx.def_map.borrow().get(&pat.id).map(|d| |
|
d.full_def()); |
|
match def { |
|
Some(DefAssociatedConst(did)) | |
|
Some(DefConst(did)) => |
|
match lookup_const_by_id(self.tcx, did, |
|
Some(pat.id)) { |
|
Some(const_expr) => { |
|
const_expr_to_pat(self.tcx, |
|
const_expr, |
|
pat.span).map(|new_pat| |
|
{ |
|
match self.renaming_map |
|
{ |
|
Some(ref mut renaming_map) |
|
=> |
|
{ |
|
record_renamings(const_expr, |
|
&pat, |
|
renaming_map); |
|
} |
|
_ |
|
=> |
|
(), |
|
} |
|
new_pat |
|
}) |
|
} |
|
None => { |
|
self.failed = true; |
|
{ |
|
(); |
|
self.tcx.sess.span_err_with_code(pat.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["statics cannot be referenced in patterns"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0158") |
|
}; |
|
pat |
|
} |
|
}, |
|
_ => noop_fold_pat(pat, self), |
|
} |
|
} |
|
_ => noop_fold_pat(pat, self), |
|
}; |
|
fn record_renamings(const_expr: &hir::Expr, |
|
substituted_pat: &hir::Pat, |
|
renaming_map: |
|
&mut FnvHashMap<(NodeId, Span), |
|
NodeId>) { |
|
let mut renaming_recorder = |
|
RenamingRecorder{substituted_node_id: |
|
substituted_pat.id, |
|
origin_span: substituted_pat.span, |
|
renaming_map: renaming_map,}; |
|
let mut id_visitor = |
|
front_util::IdVisitor::new(&mut renaming_recorder); |
|
id_visitor.visit_expr(const_expr); |
|
} |
|
} |
|
} |
|
/// Constructs a partial witness for a pattern given a list of |
|
/// patterns expanded by the specialization step. |
|
/// |
|
/// When a pattern P is discovered to be useful, this function is used bottom-up |
|
/// to reconstruct a complete witness, e.g. a pattern P' that covers a subset |
|
/// of values, V, where each value in that set is not covered by any previously |
|
/// used patterns and is covered by the pattern P'. Examples: |
|
/// |
|
/// left_ty: tuple of 3 elements |
|
/// pats: [10, 20, _] => (10, 20, _) |
|
/// |
|
/// left_ty: struct X { a: (bool, &'static str), b: usize} |
|
/// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } |
|
fn construct_witness<'a, |
|
'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, |
|
ctor: &Constructor, pats: Vec<&Pat>, |
|
left_ty: Ty<'tcx>) -> P<Pat> { |
|
let pats_len = pats.len(); |
|
let mut pats = pats.into_iter().map(|p| P((*p).clone())); |
|
let pat = |
|
match left_ty.sty { |
|
ty::TyTuple(_) => hir::PatTup(pats.collect()), |
|
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { |
|
let v = adt.variant_of_ctor(ctor); |
|
match v.kind() { |
|
VariantKind::Struct => { |
|
let field_pats: Vec<_> = |
|
v.fields.iter().zip(pats).filter(|&(_, |
|
ref pat)| |
|
pat.node |
|
!= |
|
hir::PatWild).map(|(field, |
|
pat)| |
|
Spanned{span: |
|
DUMMY_SP, |
|
node: |
|
hir::FieldPat{name: |
|
field.name, |
|
pat: |
|
pat, |
|
is_shorthand: |
|
false,},}).collect(); |
|
let has_more_fields = |
|
field_pats.len() < pats_len; |
|
hir::PatStruct(def_to_path(cx.tcx, v.did), |
|
field_pats, has_more_fields) |
|
} |
|
_ => { |
|
hir::PatEnum(def_to_path(cx.tcx, v.did), |
|
Some(pats.collect())) |
|
} |
|
} |
|
} |
|
ty::TyRef(_, ty::TypeAndMut { ty, mutbl }) => { |
|
match ty.sty { |
|
ty::TyArray(_, n) => |
|
match ctor { |
|
&Single => { |
|
{ |
|
match (&(pats_len), &(n)) { |
|
(left_val, right_val) => { |
|
if !(*left_val == *right_val) |
|
{ |
|
{ |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["assertion failed: `(left == right)` (left: `", |
|
"`, right: `", |
|
"`)"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&left_val, |
|
&right_val) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/middle/check_match.rs", |
|
541u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
}; |
|
hir::PatVec(pats.collect(), None, |
|
<[_]>::into_vec(::std::boxed::Box::new([]))) |
|
} |
|
_ => { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/middle/check_match.rs", |
|
544u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
}, |
|
ty::TySlice(_) => |
|
match ctor { |
|
&Slice(n) => { |
|
{ |
|
match (&(pats_len), &(n)) { |
|
(left_val, right_val) => { |
|
if !(*left_val == *right_val) |
|
{ |
|
{ |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["assertion failed: `(left == right)` (left: `", |
|
"`, right: `", |
|
"`)"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&left_val, |
|
&right_val) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/middle/check_match.rs", |
|
548u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
}; |
|
hir::PatVec(pats.collect(), None, |
|
<[_]>::into_vec(::std::boxed::Box::new([]))) |
|
} |
|
_ => { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/middle/check_match.rs", |
|
551u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
}, |
|
ty::TyStr => hir::PatWild, |
|
_ => { |
|
{ |
|
match (&(pats_len), &(1)) { |
|
(left_val, right_val) => { |
|
if !(*left_val == *right_val) { |
|
{ |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["assertion failed: `(left == right)` (left: `", |
|
"`, right: `", |
|
"`)"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&left_val, |
|
&right_val) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/middle/check_match.rs", |
|
556u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
}; |
|
hir::PatRegion(pats.nth(0).unwrap(), mutbl) |
|
} |
|
} |
|
} |
|
ty::TyArray(_, len) => { |
|
{ |
|
match (&(pats_len), &(len)) { |
|
(left_val, right_val) => { |
|
if !(*left_val == *right_val) { |
|
{ |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["assertion failed: `(left == right)` (left: `", |
|
"`, right: `", |
|
"`)"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&left_val, |
|
&right_val) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Debug::fmt)], |
|
}), |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) |
|
= |
|
("src/librustc/middle/check_match.rs", |
|
563u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
} |
|
} |
|
}; |
|
hir::PatVec(pats.collect(), None, |
|
<[_]>::into_vec(::std::boxed::Box::new([]))) |
|
} |
|
_ => { |
|
match *ctor { |
|
ConstantValue(ref v) => |
|
hir::PatLit(const_val_to_expr(v)), |
|
_ => hir::PatWild, |
|
} |
|
} |
|
}; |
|
P(hir::Pat{id: 0, node: pat, span: DUMMY_SP,}) |
|
} |
|
impl <'tcx, 'container> ty::AdtDefData<'tcx, 'container> { |
|
fn variant_of_ctor(&self, ctor: &Constructor) |
|
-> &VariantDefData<'tcx, 'container> { |
|
match ctor { |
|
&Variant(vid) => self.variant_with_id(vid), |
|
_ => self.struct_variant(), |
|
} |
|
} |
|
} |
|
fn missing_constructor(cx: &MatchCheckCtxt, |
|
&Matrix(ref rows): &Matrix, left_ty: Ty, |
|
max_slice_length: usize) |
|
-> Option<Constructor> { |
|
let used_constructors: Vec<Constructor> = |
|
rows.iter().flat_map(|row| |
|
pat_constructors(cx, row[0], left_ty, |
|
max_slice_length)).collect(); |
|
all_constructors(cx, left_ty, |
|
max_slice_length).into_iter().find(|c| |
|
!used_constructors.contains(c)) |
|
} |
|
/// This determines the set of all possible constructors of a pattern matching |
|
/// values of type `left_ty`. For vectors, this would normally be an infinite set |
|
/// but is instead bounded by the maximum fixed length of slice patterns in |
|
/// the column of patterns being analyzed. |
|
fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty, |
|
max_slice_length: usize) -> Vec<Constructor> { |
|
match left_ty.sty { |
|
ty::TyBool => |
|
[true, |
|
false].iter().map(|b| |
|
ConstantValue(ConstVal::Bool(*b))).collect(), |
|
ty::TyRef(_, ty::TypeAndMut { ty, .. }) => |
|
match ty.sty { |
|
ty::TySlice(_) => |
|
(0..max_slice_length + |
|
1).map(|length| Slice(length)).collect(), |
|
_ => <[_]>::into_vec(::std::boxed::Box::new([Single])), |
|
}, |
|
ty::TyEnum(def, _) => |
|
def.variants.iter().map(|v| Variant(v.did)).collect(), |
|
_ => <[_]>::into_vec(::std::boxed::Box::new([Single])), |
|
} |
|
} |
|
fn is_useful(cx: &MatchCheckCtxt, matrix: &Matrix, v: &[&Pat], |
|
witness: WitnessPreference) -> Usefulness { |
|
let &Matrix(ref rows) = matrix; |
|
if false { |
|
{ |
|
static LOC: ::log::LogLocation = |
|
::log::LogLocation{line: 643u32, |
|
file: |
|
"src/librustc/middle/check_match.rs", |
|
module_path: |
|
"rustc::middle::check_match",}; |
|
let lvl = ::log::DEBUG; |
|
if { |
|
let lvl = lvl; |
|
(lvl != ::log::DEBUG || false) && |
|
lvl <= ::log::log_level() && |
|
::log::mod_enabled(lvl, |
|
"rustc::middle::check_match") |
|
} { |
|
::log::log(lvl, &LOC, |
|
::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&[""]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&matrix,) |
|
{ |
|
(__arg0,) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt)], |
|
})) |
|
} |
|
} |
|
}; |
|
if rows.is_empty() { |
|
return match witness { |
|
ConstructWitness => |
|
UsefulWithWitness(<[_]>::into_vec(::std::boxed::Box::new([]))), |
|
LeaveOutWitness => Useful, |
|
}; |
|
} |
|
if rows[0].is_empty() { return NotUseful; } |
|
if !rows.iter().all(|r| r.len() == v.len()) { |
|
{ |
|
::std::rt::begin_unwind("assertion failed: rows.iter().all(|r| r.len() == v.len())", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, u32) = |
|
("src/librustc/middle/check_match.rs", |
|
653u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
}; |
|
let real_pat = |
|
match rows.iter().find(|r| (*r)[0].id != DUMMY_NODE_ID) { |
|
Some(r) => raw_pat(r[0]), |
|
None if v.is_empty() => return NotUseful, |
|
None => v[0], |
|
}; |
|
let left_ty = |
|
if real_pat.id == DUMMY_NODE_ID { |
|
cx.tcx.mk_nil() |
|
} else { |
|
let left_ty = cx.tcx.pat_ty(&*real_pat); |
|
match real_pat.node { |
|
hir::PatIdent(hir::BindByRef(..), _, _) => { |
|
left_ty.builtin_deref(false, |
|
NoPreference).unwrap().ty |
|
} |
|
_ => left_ty, |
|
} |
|
}; |
|
let max_slice_length = |
|
rows.iter().filter_map(|row| |
|
match row[0].node { |
|
hir::PatVec(ref before, _, |
|
ref after) => |
|
Some(before.len() + |
|
after.len()), |
|
_ => None, |
|
}).max().map_or(0, |v| v + 1); |
|
let constructors = |
|
pat_constructors(cx, v[0], left_ty, max_slice_length); |
|
if constructors.is_empty() { |
|
match missing_constructor(cx, matrix, left_ty, |
|
max_slice_length) { |
|
None => { |
|
all_constructors(cx, left_ty, |
|
max_slice_length).into_iter().map(|c| |
|
{ |
|
match is_useful_specialized(cx, |
|
matrix, |
|
v, |
|
c.clone(), |
|
left_ty, |
|
witness) |
|
{ |
|
UsefulWithWitness(pats) |
|
=> |
|
UsefulWithWitness({ |
|
let arity = |
|
constructor_arity(cx, |
|
&c, |
|
left_ty); |
|
let mut result = |
|
{ |
|
let pat_slice = |
|
&pats[..]; |
|
let subpats: |
|
Vec<_> = |
|
(0..arity).map(|i| |
|
{ |
|
pat_slice.get(i).map_or(DUMMY_WILD_PAT, |
|
|p| |
|
&**p) |
|
}).collect(); |
|
<[_]>::into_vec(::std::boxed::Box::new([construct_witness(cx, |
|
&c, |
|
subpats, |
|
left_ty)])) |
|
}; |
|
result.extend(pats.into_iter().skip(arity)); |
|
result |
|
}), |
|
result |
|
=> |
|
result, |
|
} |
|
}).find(|result| |
|
result |
|
!= |
|
&NotUseful).unwrap_or(NotUseful) |
|
} |
|
Some(constructor) => { |
|
let matrix = |
|
rows.iter().filter_map(|r| { |
|
if pat_is_binding_or_wild(&cx.tcx.def_map.borrow(), |
|
raw_pat(r[0])) |
|
{ |
|
Some(r[1..].to_vec()) |
|
} else { None } |
|
}).collect(); |
|
match is_useful(cx, &matrix, &v[1..], witness) { |
|
UsefulWithWitness(pats) => { |
|
let arity = |
|
constructor_arity(cx, &constructor, |
|
left_ty); |
|
let wild_pats = |
|
::std::vec::from_elem(DUMMY_WILD_PAT, |
|
arity); |
|
let enum_pat = |
|
construct_witness(cx, &constructor, |
|
wild_pats, left_ty); |
|
let mut new_pats = |
|
<[_]>::into_vec(::std::boxed::Box::new([enum_pat])); |
|
new_pats.extend(pats); |
|
UsefulWithWitness(new_pats) |
|
} |
|
result => result, |
|
} |
|
} |
|
} |
|
} else { |
|
constructors.into_iter().map(|c| |
|
is_useful_specialized(cx, |
|
matrix, |
|
v, |
|
c.clone(), |
|
left_ty, |
|
witness)).find(|result| |
|
result |
|
!= |
|
&NotUseful).unwrap_or(NotUseful) |
|
} |
|
} |
|
fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix, |
|
v: &[&Pat], ctor: Constructor, lty: Ty, |
|
witness: WitnessPreference) -> Usefulness { |
|
let arity = constructor_arity(cx, &ctor, lty); |
|
let matrix = |
|
Matrix(m.iter().filter_map(|r| { |
|
specialize(cx, &r[..], &ctor, 0, |
|
arity) }).collect()); |
|
match specialize(cx, v, &ctor, 0, arity) { |
|
Some(v) => is_useful(cx, &matrix, &v[..], witness), |
|
None => NotUseful, |
|
} |
|
} |
|
/// Determines the constructors that the given pattern can be specialized to. |
|
/// |
|
/// In most cases, there's only one constructor that a specific pattern |
|
/// represents, such as a specific enum variant or a specific literal value. |
|
/// Slice patterns, however, can match slices of different lengths. For instance, |
|
/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on. |
|
/// |
|
/// On the other hand, a wild pattern and an identifier pattern cannot be |
|
/// specialized in any way. |
|
fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, left_ty: Ty, |
|
max_slice_length: usize) -> Vec<Constructor> { |
|
let pat = raw_pat(p); |
|
match pat.node { |
|
hir::PatIdent(..) => |
|
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| |
|
d.full_def()) |
|
{ |
|
Some(DefConst(..)) | Some(DefAssociatedConst(..)) => |
|
cx.tcx.sess.span_bug(pat.span, |
|
"const pattern should\'ve been rewritten"), |
|
Some(DefStruct(_)) => |
|
<[_]>::into_vec(::std::boxed::Box::new([Single])), |
|
Some(DefVariant(_, id, _)) => |
|
<[_]>::into_vec(::std::boxed::Box::new([Variant(id)])), |
|
_ => <[_]>::into_vec(::std::boxed::Box::new([])), |
|
}, |
|
hir::PatEnum(..) => |
|
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| |
|
d.full_def()) |
|
{ |
|
Some(DefConst(..)) | Some(DefAssociatedConst(..)) => |
|
cx.tcx.sess.span_bug(pat.span, |
|
"const pattern should\'ve been rewritten"), |
|
Some(DefVariant(_, id, _)) => |
|
<[_]>::into_vec(::std::boxed::Box::new([Variant(id)])), |
|
_ => <[_]>::into_vec(::std::boxed::Box::new([Single])), |
|
}, |
|
hir::PatQPath(..) => |
|
cx.tcx.sess.span_bug(pat.span, |
|
"const pattern should\'ve been rewritten"), |
|
hir::PatStruct(..) => |
|
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| |
|
d.full_def()) |
|
{ |
|
Some(DefConst(..)) | Some(DefAssociatedConst(..)) => |
|
cx.tcx.sess.span_bug(pat.span, |
|
"const pattern should\'ve been rewritten"), |
|
Some(DefVariant(_, id, _)) => |
|
<[_]>::into_vec(::std::boxed::Box::new([Variant(id)])), |
|
_ => <[_]>::into_vec(::std::boxed::Box::new([Single])), |
|
}, |
|
hir::PatLit(ref expr) => |
|
<[_]>::into_vec(::std::boxed::Box::new([ConstantValue(eval_const_expr(cx.tcx, |
|
&**expr))])), |
|
hir::PatRange(ref lo, ref hi) => |
|
<[_]>::into_vec(::std::boxed::Box::new([ConstantRange(eval_const_expr(cx.tcx, |
|
&**lo), |
|
eval_const_expr(cx.tcx, |
|
&**hi))])), |
|
hir::PatVec(ref before, ref slice, ref after) => |
|
match left_ty.sty { |
|
ty::TyArray(_, _) => |
|
<[_]>::into_vec(::std::boxed::Box::new([Single])), |
|
_ => |
|
if slice.is_some() { |
|
(before.len() + |
|
after.len()..max_slice_length + |
|
1).map(|length| |
|
Slice(length)).collect() |
|
} else { |
|
<[_]>::into_vec(::std::boxed::Box::new([Slice(before.len() |
|
+ |
|
after.len())])) |
|
}, |
|
}, |
|
hir::PatBox(_) | hir::PatTup(_) | hir::PatRegion(..) => |
|
<[_]>::into_vec(::std::boxed::Box::new([Single])), |
|
hir::PatWild => <[_]>::into_vec(::std::boxed::Box::new([])), |
|
} |
|
} |
|
/// This computes the arity of a constructor. The arity of a constructor |
|
/// is how many subpattern patterns of that constructor should be expanded to. |
|
/// |
|
/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3. |
|
/// A struct pattern's arity is the number of fields it contains, etc. |
|
pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, |
|
ty: Ty) -> usize { |
|
match ty.sty { |
|
ty::TyTuple(ref fs) => fs.len(), |
|
ty::TyBox(_) => 1, |
|
ty::TyRef(_, ty::TypeAndMut { ty, .. }) => |
|
match ty.sty { |
|
ty::TySlice(_) => |
|
match *ctor { |
|
Slice(length) => length, |
|
ConstantValue(_) => 0, |
|
_ => { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/middle/check_match.rs", |
|
817u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
}, |
|
ty::TyStr => 0, |
|
_ => 1, |
|
}, |
|
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { |
|
adt.variant_of_ctor(ctor).fields.len() |
|
} |
|
ty::TyArray(_, n) => n, |
|
_ => 0, |
|
} |
|
} |
|
fn range_covered_by_constructor(ctor: &Constructor, from: &ConstVal, |
|
to: &ConstVal) -> Option<bool> { |
|
let (c_from, c_to) = |
|
match *ctor { |
|
ConstantValue(ref value) => (value, value), |
|
ConstantRange(ref from, ref to) => (from, to), |
|
Single => return Some(true), |
|
_ => { |
|
{ |
|
::std::rt::begin_unwind("internal error: entered unreachable code", |
|
{ |
|
static _FILE_LINE: |
|
(&'static str, |
|
u32) = |
|
("src/librustc/middle/check_match.rs", |
|
836u32); |
|
&_FILE_LINE |
|
}) |
|
} |
|
} |
|
}; |
|
let cmp_from = compare_const_vals(c_from, from); |
|
let cmp_to = compare_const_vals(c_to, to); |
|
match (cmp_from, cmp_to) { |
|
(Some(cmp_from), Some(cmp_to)) => { |
|
Some(cmp_from != Ordering::Less && |
|
cmp_to != Ordering::Greater) |
|
} |
|
_ => None, |
|
} |
|
} |
|
/// This is the main specialization step. It expands the first pattern in the given row |
|
/// into `arity` patterns based on the constructor. For most patterns, the step is trivial, |
|
/// for instance tuple patterns are flattened and box patterns expand into their inner pattern. |
|
/// |
|
/// OTOH, slice patterns with a subslice pattern (..tail) can be expanded into multiple |
|
/// different patterns. |
|
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing |
|
/// fields filled with wild patterns. |
|
pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], |
|
constructor: &Constructor, col: usize, |
|
arity: usize) -> Option<Vec<&'a Pat>> { |
|
let &Pat { id: pat_id, ref node, span: pat_span } = |
|
raw_pat(r[col]); |
|
let head: Option<Vec<&Pat>> = |
|
match *node { |
|
hir::PatWild => |
|
Some(::std::vec::from_elem(DUMMY_WILD_PAT, arity)), |
|
hir::PatIdent(_, _, _) => { |
|
let opt_def = |
|
cx.tcx.def_map.borrow().get(&pat_id).map(|d| |
|
d.full_def()); |
|
match opt_def { |
|
Some(DefConst(..)) | Some(DefAssociatedConst(..)) |
|
=> |
|
cx.tcx.sess.span_bug(pat_span, |
|
"const pattern should\'ve been rewritten"), |
|
Some(DefVariant(_, id, _)) => |
|
if *constructor == Variant(id) { |
|
Some(<[_]>::into_vec(::std::boxed::Box::new([]))) |
|
} else { None }, |
|
_ => |
|
Some(::std::vec::from_elem(DUMMY_WILD_PAT, |
|
arity)), |
|
} |
|
} |
|
hir::PatEnum(_, ref args) => { |
|
let def = |
|
cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def(); |
|
match def { |
|
DefConst(..) | DefAssociatedConst(..) => |
|
cx.tcx.sess.span_bug(pat_span, |
|
"const pattern should\'ve been rewritten"), |
|
DefVariant(_, id, _) if |
|
*constructor != Variant(id) => None, |
|
DefVariant(..) | DefStruct(..) => { |
|
Some(match args { |
|
&Some(ref args) => |
|
args.iter().map(|p| &**p).collect(), |
|
&None => |
|
::std::vec::from_elem(DUMMY_WILD_PAT, |
|
arity), |
|
}) |
|
} |
|
_ => None, |
|
} |
|
} |
|
hir::PatQPath(_, _) => { |
|
cx.tcx.sess.span_bug(pat_span, |
|
"const pattern should\'ve been rewritten") |
|
} |
|
hir::PatStruct(_, ref pattern_fields, _) => { |
|
let def = |
|
cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def(); |
|
let adt = |
|
cx.tcx.node_id_to_type(pat_id).ty_adt_def().unwrap(); |
|
let variant = adt.variant_of_ctor(constructor); |
|
let def_variant = adt.variant_of_def(def); |
|
if variant.did == def_variant.did { |
|
Some(variant.fields.iter().map(|sf| { |
|
match pattern_fields.iter().find(|f| |
|
f.node.name |
|
== |
|
sf.name) |
|
{ |
|
Some(ref f) => |
|
&*f.node.pat, |
|
_ => |
|
DUMMY_WILD_PAT, |
|
} }).collect()) |
|
} else { None } |
|
} |
|
hir::PatTup(ref args) => |
|
Some(args.iter().map(|p| &**p).collect()), |
|
hir::PatBox(ref inner) | hir::PatRegion(ref inner, _) => |
|
Some(<[_]>::into_vec(::std::boxed::Box::new([&**inner]))), |
|
hir::PatLit(ref expr) => { |
|
let expr_value = eval_const_expr(cx.tcx, &**expr); |
|
match range_covered_by_constructor(constructor, |
|
&expr_value, |
|
&expr_value) { |
|
Some(true) => |
|
Some(<[_]>::into_vec(::std::boxed::Box::new([]))), |
|
Some(false) => None, |
|
None => { |
|
{ |
|
(); |
|
cx.tcx.sess.span_err_with_code(pat_span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mismatched types between arms"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0298") |
|
}; |
|
None |
|
} |
|
} |
|
} |
|
hir::PatRange(ref from, ref to) => { |
|
let from_value = eval_const_expr(cx.tcx, &**from); |
|
let to_value = eval_const_expr(cx.tcx, &**to); |
|
match range_covered_by_constructor(constructor, |
|
&from_value, |
|
&to_value) { |
|
Some(true) => |
|
Some(<[_]>::into_vec(::std::boxed::Box::new([]))), |
|
Some(false) => None, |
|
None => { |
|
{ |
|
(); |
|
cx.tcx.sess.span_err_with_code(pat_span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["mismatched types between arms"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match () |
|
{ |
|
() |
|
=> |
|
[], |
|
})), |
|
"E0299") |
|
}; |
|
None |
|
} |
|
} |
|
} |
|
hir::PatVec(ref before, ref slice, ref after) => { |
|
match *constructor { |
|
Single => { |
|
let mut pats: Vec<&Pat> = |
|
before.iter().map(|p| &**p).collect(); |
|
pats.extend(repeat(DUMMY_WILD_PAT).take(arity |
|
- |
|
before.len() |
|
- |
|
after.len())); |
|
pats.extend(after.iter().map(|p| &**p)); |
|
Some(pats) |
|
} |
|
Slice(length) if |
|
before.len() + after.len() <= length && |
|
slice.is_some() => { |
|
let mut pats: Vec<&Pat> = |
|
before.iter().map(|p| &**p).collect(); |
|
pats.extend(repeat(DUMMY_WILD_PAT).take(arity |
|
- |
|
before.len() |
|
- |
|
after.len())); |
|
pats.extend(after.iter().map(|p| &**p)); |
|
Some(pats) |
|
} |
|
Slice(length) if |
|
before.len() + after.len() == length => { |
|
let mut pats: Vec<&Pat> = |
|
before.iter().map(|p| &**p).collect(); |
|
pats.extend(after.iter().map(|p| &**p)); |
|
Some(pats) |
|
} |
|
SliceWithSubslice(prefix, suffix) if |
|
before.len() == prefix && after.len() == suffix && |
|
slice.is_some() => { |
|
let mut pats: Vec<&Pat> = |
|
before.iter().map(|p| &**p).collect(); |
|
pats.extend(after.iter().map(|p| &**p)); |
|
Some(pats) |
|
} |
|
_ => None, |
|
} |
|
} |
|
}; |
|
head.map(|mut head| { head.extend_from_slice(&r[..col]); |
|
head.extend_from_slice(&r[col + 1..]); head }) |
|
} |
|
fn check_local(cx: &mut MatchCheckCtxt, loc: &hir::Local) { |
|
intravisit::walk_local(cx, loc); |
|
let pat = |
|
StaticInliner::new(cx.tcx, None).fold_pat(loc.pat.clone()); |
|
check_irrefutable(cx, &pat, false); |
|
check_legality_of_move_bindings(cx, false, |
|
slice::ref_slice(&loc.pat)); |
|
check_legality_of_bindings_in_at_patterns(cx, &*loc.pat); |
|
} |
|
fn check_fn(cx: &mut MatchCheckCtxt, kind: FnKind, decl: &hir::FnDecl, |
|
body: &hir::Block, sp: Span, fn_id: NodeId) { |
|
match kind { |
|
FnKind::Closure => { } |
|
_ => |
|
cx.param_env = ParameterEnvironment::for_item(cx.tcx, fn_id), |
|
} |
|
intravisit::walk_fn(cx, kind, decl, body, sp); |
|
{ |
|
let result = |
|
match ::std::iter::IntoIterator::into_iter(&decl.inputs) { |
|
mut iter => |
|
loop { |
|
match ::std::iter::Iterator::next(&mut iter) { |
|
::std::option::Option::Some(input) => { |
|
check_irrefutable(cx, &input.pat, true); |
|
check_legality_of_move_bindings(cx, false, |
|
slice::ref_slice(&input.pat)); |
|
check_legality_of_bindings_in_at_patterns(cx, |
|
&*input.pat); |
|
} |
|
::std::option::Option::None => break , |
|
} |
|
}, |
|
}; |
|
result |
|
} |
|
} |
|
fn check_irrefutable(cx: &MatchCheckCtxt, pat: &Pat, |
|
is_fn_arg: bool) { |
|
let origin = |
|
if is_fn_arg { "function argument" } else { "local binding" }; |
|
is_refutable(cx, pat, |uncovered_pat| { |
|
{ |
|
(); |
|
cx.tcx.sess.span_err_with_code(pat.span, |
|
&::std::fmt::format(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["refutable pattern in ", |
|
": `", |
|
"` not covered"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&origin, |
|
&pat_to_string(uncovered_pat)) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Display::fmt), |
|
::std::fmt::ArgumentV1::new(__arg1, |
|
::std::fmt::Display::fmt)], |
|
})), |
|
"E0005") |
|
}; }); |
|
} |
|
fn is_refutable<A, F>(cx: &MatchCheckCtxt, pat: &Pat, refutable: F) |
|
-> Option<A> where F: FnOnce(&Pat) -> A { |
|
let pats = |
|
Matrix(<[_]>::into_vec(::std::boxed::Box::new([<[_]>::into_vec(::std::boxed::Box::new([pat]))]))); |
|
match is_useful(cx, &pats, &[DUMMY_WILD_PAT], ConstructWitness) { |
|
UsefulWithWitness(pats) => { |
|
{ |
|
match (&(pats.len()), &(1)) { |
|
(left_val, right_val) => { |
|
if !(*left_val == *right_val) { |
|
{ |
|
::std::rt::begin_unwind_fmt(::std::fmt::Arguments::new_v1({ |
|
static __STATIC_FMTSTR: |
|
&'static [&'static str] |
|
= |
|
&["assertion failed: `(left == right)` (left: `", |
|
"`, right: `", |
|
"`)"]; |
|
__STATIC_FMTSTR |
|
}, |
|
&match (&left_val, |
|
&right_val) |
|
{ |
|
(__arg0, |
|
__arg1) |
|
=> |
|
[::std::fmt::ArgumentV1::new(__arg0, |
|
::std::fmt::Debug::fmt), |