probe CFG_GDB gdb
probe CFG_LLDB lldb
+if [ ! -z "$CFG_GDB" ]
+then
+ # Extract the version
+ CFG_GDB_VERSION=$($CFG_GDB --version 2>/dev/null | head -1)
+ putvar CFG_GDB_VERSION
+fi
+
if [ ! -z "$CFG_LLDB" ]
then
# If CFG_LLDB_PYTHON_DIR is not already set from the outside and valid, try to read it from
--stage-id stage$(1)-$(2) \
--target $(2) \
--host $(3) \
+ --gdb-version="$(CFG_GDB_VERSION)" \
--android-cross-path=$(CFG_ANDROID_CROSS_PATH) \
--adb-path=$(CFG_ADB) \
--adb-test-dir=$(CFG_ADB_TEST_DIR) \
// Host triple for the compiler being invoked
pub host: String,
+ // Version of GDB
+ pub gdb_version: Option<String>,
+
// Path to the android tools
pub android_cross_path: Path,
optflag("", "jit", "run tests under the JIT"),
optopt("", "target", "the target to build for", "TARGET"),
optopt("", "host", "the host to build for", "HOST"),
+ optopt("", "gdb-version", "the version of GDB used", "MAJOR.MINOR"),
optopt("", "android-cross-path", "Android NDK standalone path", "PATH"),
optopt("", "adb-path", "path to the android debugger", "PATH"),
optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
jit: matches.opt_present("jit"),
target: opt_str2(matches.opt_str("target")),
host: opt_str2(matches.opt_str("host")),
+ gdb_version: extract_gdb_version(matches.opt_str("gdb-version")),
android_cross_path: opt_path(matches, "android-cross-path"),
adb_path: opt_str2(matches.opt_str("adb-path")),
adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")),
runtest::run_metrics(config, testfile, mm)
})
}
+
+fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> {
+ match full_version_line {
+ Some(ref full_version_line)
+ if full_version_line.as_slice().trim().len() > 0 => {
+ let full_version_line = full_version_line.as_slice().trim();
+
+ let re = Regex::new(r"(^|[^0-9])([0-9]\.[0-9])([^0-9]|$)").unwrap();
+
+ match re.captures(full_version_line) {
+ Some(captures) => {
+ Some(captures.at(2).to_string())
+ }
+ None => {
+ println!("Could not extract GDB version from line '{}'",
+ full_version_line);
+ None
+ }
+ }
+ },
+ _ => None
+ }
+}
\ No newline at end of file
use common;
use util;
+use std::from_str::FromStr;
+
pub struct TestProps {
// Lines that should be expected, in order, on standard out
pub error_patterns: Vec<String> ,
format!("ignore-{}",
config.stage_id.as_slice().split('-').next().unwrap())
}
+ fn ignore_gdb(config: &Config, line: &str) -> bool {
+ if config.mode != common::DebugInfoGdb {
+ return false;
+ }
- let val = iter_header(testfile, |ln| {
- if parse_name_directive(ln, "ignore-test") {
- false
- } else if parse_name_directive(ln, ignore_target(config).as_slice()) {
- false
- } else if parse_name_directive(ln, ignore_stage(config).as_slice()) {
- false
- } else if config.mode == common::Pretty &&
- parse_name_directive(ln, "ignore-pretty") {
- false
- } else if config.target != config.host &&
- parse_name_directive(ln, "ignore-cross-compile") {
- false
- } else {
- true
+ if parse_name_directive(line, "ignore-gdb") {
+ return true;
}
+
+ match config.gdb_version {
+ Some(ref actual_version) => {
+ if line.contains("min-gdb-version") {
+ let min_version = line.trim()
+ .split(' ')
+ .last()
+ .expect("Malformed GDB version directive");
+ // Ignore if actual version is smaller the minimum required
+ // version
+ gdb_version_to_int(actual_version.as_slice()) <
+ gdb_version_to_int(min_version.as_slice())
+ } else {
+ false
+ }
+ }
+ None => false
+ }
+ }
+
+ let val = iter_header(testfile, |ln| {
+ !parse_name_directive(ln, "ignore-test") &&
+ !parse_name_directive(ln, ignore_target(config).as_slice()) &&
+ !parse_name_directive(ln, ignore_stage(config).as_slice()) &&
+ !(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) &&
+ !(config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) &&
+ !ignore_gdb(config, ln) &&
+ !(config.mode == common::DebugInfoLldb && parse_name_directive(ln, "ignore-lldb"))
});
!val
None => None
}
}
+
+pub fn gdb_version_to_int(version_string: &str) -> int {
+ let error_string = format!(
+ "Encountered GDB version string with unexpected format: {}",
+ version_string);
+ let error_string = error_string.as_slice();
+
+ let components: Vec<&str> = version_string.trim().split('.').collect();
+
+ if components.len() != 2 {
+ fail!("{}", error_string);
+ }
+
+ let major: int = FromStr::from_str(components[0]).expect(error_string);
+ let minor: int = FromStr::from_str(components[1]).expect(error_string);
+
+ return major * 1000 + minor;
+}
};
let config = &mut config;
- let DebuggerCommands { commands, check_lines, .. } = parse_debugger_commands(testfile, "gdb");
+ let DebuggerCommands {
+ commands,
+ check_lines,
+ use_gdb_pretty_printer,
+ ..
+ } = parse_debugger_commands(testfile, "gdb");
let mut cmds = commands.connect("\n");
// compile test file (it should have 'compile-flags:-g' in the header)
let exe_file = make_exe_name(config, testfile);
- let mut proc_args;
let debugger_run_result;
match config.target.as_slice() {
"arm-linux-androideabi" => {
}
_=> {
+ let rust_src_root = find_rust_src_root(config)
+ .expect("Could not find Rust source root");
+ let rust_pp_module_rel_path = Path::new("./src/etc");
+ let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
+ .as_str()
+ .unwrap()
+ .to_string();
// write debugger script
- let script_str = [
- "set charset UTF-8".to_string(),
- cmds,
- "quit\n".to_string()
- ].connect("\n");
+ let mut script_str = String::with_capacity(2048);
+
+ script_str.push_str("set charset UTF-8\n");
+ script_str.push_str("show version\n");
+
+ match config.gdb_version {
+ Some(ref version) => {
+ println!("NOTE: compiletest thinks it is using GDB version {}",
+ version.as_slice());
+
+ if header::gdb_version_to_int(version.as_slice()) >
+ header::gdb_version_to_int("7.4") {
+ // Add the directory containing the pretty printers to
+ // GDB's script auto loading safe path ...
+ script_str.push_str(
+ format!("add-auto-load-safe-path {}\n",
+ rust_pp_module_abs_path.as_slice())
+ .as_slice());
+ // ... and also the test directory
+ script_str.push_str(
+ format!("add-auto-load-safe-path {}\n",
+ config.build_base.as_str().unwrap())
+ .as_slice());
+ }
+ }
+ _ => {
+ println!("NOTE: compiletest does not know which version of \
+ GDB it is using");
+ }
+ }
+
+ // Load the target executable
+ script_str.push_str(format!("file {}\n",
+ exe_file.as_str().unwrap())
+ .as_slice());
+
+ script_str.push_str(cmds.as_slice());
+ script_str.push_str("quit\n");
+
debug!("script_str = {}", script_str);
dump_output_file(config,
testfile,
script_str.as_slice(),
"debugger.script");
+ if use_gdb_pretty_printer {
+ // Only emit the gdb auto-loading script if pretty printers
+ // should actually be loaded
+ dump_gdb_autoload_script(config, testfile);
+ }
+
// run debugger script with gdb
#[cfg(windows)]
fn debugger() -> String {
vec!("-quiet".to_string(),
"-batch".to_string(),
"-nx".to_string(),
- format!("-command={}", debugger_script.as_str().unwrap()),
- exe_file.as_str().unwrap().to_string());
- proc_args = ProcArgs {
+ format!("-command={}", debugger_script.as_str().unwrap()));
+
+ let proc_args = ProcArgs {
prog: debugger(),
args: debugger_opts,
};
+
+ let environment = vec![("PYTHONPATH".to_string(), rust_pp_module_abs_path)];
+
debugger_run_result = compose_and_run(config,
testfile,
proc_args,
- Vec::new(),
+ environment,
config.run_lib_path.as_slice(),
None,
None);
}
check_debugger_output(&debugger_run_result, check_lines.as_slice());
+
+ fn dump_gdb_autoload_script(config: &Config, testfile: &Path) {
+ let mut script_path = output_base_name(config, testfile);
+ let mut script_file_name = script_path.filename().unwrap().to_vec();
+ script_file_name.push_all("-gdb.py".as_bytes());
+ script_path.set_filename(script_file_name.as_slice());
+
+ let script_content = "import gdb_rust_pretty_printing\n\
+ gdb_rust_pretty_printing.register_printers(gdb.current_objfile())\n"
+ .as_bytes();
+
+ File::create(&script_path).write(script_content).unwrap();
+ }
+}
+
+fn find_rust_src_root(config: &Config) -> Option<Path> {
+ let mut path = config.src_base.clone();
+ let path_postfix = Path::new("src/etc/lldb_batchmode.py");
+
+ while path.pop() {
+ if path.join(path_postfix.clone()).is_file() {
+ return Some(path);
+ }
+ }
+
+ return None;
}
fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) {
let DebuggerCommands {
commands,
check_lines,
- breakpoint_lines
+ breakpoint_lines,
+ ..
} = parse_debugger_commands(testfile, "lldb");
// Write debugger script:
commands: Vec<String>,
check_lines: Vec<String>,
breakpoint_lines: Vec<uint>,
+ use_gdb_pretty_printer: bool
}
fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
let mut breakpoint_lines = vec!();
let mut commands = vec!();
let mut check_lines = vec!();
+ let mut use_gdb_pretty_printer = false;
let mut counter = 1;
let mut reader = BufferedReader::new(File::open(file_path).unwrap());
for line in reader.lines() {
breakpoint_lines.push(counter);
}
+ if line.as_slice().contains("gdb-use-pretty-printer") {
+ use_gdb_pretty_printer = true;
+ }
+
header::parse_name_value_directive(
line.as_slice(),
command_directive.as_slice()).map(|cmd| {
DebuggerCommands {
commands: commands,
check_lines: check_lines,
- breakpoint_lines: breakpoint_lines
+ breakpoint_lines: breakpoint_lines,
+ use_gdb_pretty_printer: use_gdb_pretty_printer,
}
}
#[cfg(target_os = "win32", target_arch = "x86")]
#[link(name = "kernel32")]
-#[allow(non_snake_case_functions)]
+#[allow(non_snake_case)]
extern "stdcall" {
fn SetEnvironmentVariableA(n: *const u8, v: *const u8) -> libc::c_int;
}
# The "nullable pointer optimization"
Certain types are defined to not be `null`. This includes references (`&T`,
-`&mut T`), owning pointers (`~T`), and function pointers (`extern "abi"
-fn()`). When interfacing with C, pointers that might be null are often used.
+`&mut T`), boxes (`Box<T>`), and function pointers (`extern "abi" fn()`).
+When interfacing with C, pointers that might be null are often used.
As a special case, a generic `enum` that contains exactly two variants, one of
which contains no data and the other containing a single field, is eligible
for the "nullable pointer optimization". When such an enum is instantiated
This part is coming soon.
+# Patterns and `ref`
+
+When you're trying to match something that's stored in a pointer, there may be
+a situation where matching directly isn't the best option available. Let's see
+how to properly handle this:
+
+```{rust,ignore}
+fn possibly_print(x: &Option<String>) {
+ match *x {
+ // BAD: cannot move out of a `&`
+ Some(s) => println!("{}", s)
+
+ // GOOD: instead take a reference into the memory of the `Option`
+ Some(ref s) => println!("{}", *s),
+ None => {}
+ }
+}
+```
+
+The `ref s` here means that `s` will be of type `&String`, rather than type
+`String`.
+
+This is important when the type you're trying to get access to has a destructor
+and you don't want to move it, you just want a reference to it.
+
# Cheat Sheet
Here's a quick rundown of Rust's pointer types:
[package]
name = "hello_world"
-version = "0.1.0"
+version = "0.0.1"
authors = [ "Your name <you@example.com>" ]
[[bin]]
```{notrust,ignore}
$ cargo run
- Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
+ Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Hello, world!
```
```{notrust,ignore}
$ cargo run
- Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
+ Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 7
```{notrust,ignore}
$ cargo run
- Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
+ Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 57
```{notrust,ignore}
$ cargo run
- Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
+ Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 17
```{notrust,ignore}
$ cargo run
- Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
+ Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 58
```{notrust,ignore}
$ cargo run
- Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
+ Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 59
```{notrust,ignore}
$ cargo run
- Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
+ Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
Running `target/guessing_game`
Guess the number!
The secret number is: 61
Let's double check our work by compiling:
-```{bash,ignore}
-$ cargo build
+```{bash,notrust}
+$ cargo run
Compiling modules v0.0.1 (file:///home/you/projects/modules)
-$ ./target/modules
+ Running `target/modules`
Hello, world!
```
Rust provides six attributes to indicate the stability level of various
parts of your library. The six levels are:
-* deprecated: this item should no longer be used. No guarantee of backwards
+* deprecated: This item should no longer be used. No guarantee of backwards
compatibility.
* experimental: This item was only recently introduced or is otherwise in a
state of flux. It may change significantly, or even be removed. No guarantee
Rust can't find this function. That makes sense, as we didn't write it yet!
-In order to share this codes with our tests, we'll need to make a library crate.
+In order to share this code with our tests, we'll need to make a library crate.
This is also just good software design: as we mentioned before, it's a good idea
to put most of your functionality into a library crate, and have your executable
crate use that library. This allows for code re-use.
deallocated, leaving it up to your runtime can make this difficult.
Rust chooses a different path, and that path is called **ownership**. Any
-binding that creates a resource is the **owner** of that resource. Being an
-owner gives you three privileges, with two restrictions:
+binding that creates a resource is the **owner** of that resource.
+
+Being an owner affords you some privileges:
1. You control when that resource is deallocated.
2. You may lend that resource, immutably, to as many borrowers as you'd like.
-3. You may lend that resource, mutably, to a single borrower. **BUT**
-4. Once you've done so, you may not also lend it out otherwise, mutably or
- immutably.
-5. You may not lend it out mutably if you're currently lending it to someone.
+3. You may lend that resource, mutably, to a single borrower.
+
+But it also comes with some restrictions:
+
+1. If someone is borrowing your resource (either mutably or immutably), you may
+ not mutate the resource or mutably lend it to someone.
+2. If someone is mutably borrowing your resource, you may not lend it out at
+ all (mutably or immutably) or access it in any way.
What's up with all this 'lending' and 'borrowing'? When you allocate memory,
you get a pointer to that memory. This pointer allows you to manipulate said
# Unsafe
-Finally, there's one more concept that you should be aware in Rust: `unsafe`.
+Finally, there's one more Rust concept that you should be aware of: `unsafe`.
There are two circumstances where Rust's safety provisions don't work well.
The first is when interfacing with C code, and the second is when building
certain kinds of abstractions.
* `begin_unwind`
: ___Needs filling in___
+* `managed_bound`
+ : This type implements "managed"
* `no_copy_bound`
: This type does not implement "copy", even if eligible
* `no_send_bound`
: This type does not implement "send", even if eligible
-* `no_sync_bound`
- : This type does not implement "sync", even if eligible
-* `managed_bound`
- : This type implements "managed"
+* `no_share_bound`
+ : This type does not implement "share", even if eligible
* `eh_personality`
: ___Needs filling in___
* `exchange_free`
--- /dev/null
+# Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+import gdb
+
+#===============================================================================
+# GDB Pretty Printing Module for Rust
+#===============================================================================
+
+def register_printers(objfile):
+ "Registers Rust pretty printers for the given objfile"
+ objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
+
+def rust_pretty_printer_lookup_function(val):
+ "Returns the correct Rust pretty printer for the given value if there is one"
+ type_code = val.type.code
+
+ if type_code == gdb.TYPE_CODE_STRUCT:
+ struct_kind = classify_struct(val.type)
+
+ if struct_kind == STRUCT_KIND_STR_SLICE:
+ return RustStringSlicePrinter(val)
+
+ if struct_kind == STRUCT_KIND_TUPLE:
+ return RustTuplePrinter(val)
+
+ if struct_kind == STRUCT_KIND_TUPLE_STRUCT:
+ return RustTupleStructPrinter(val, False)
+
+ if struct_kind == STRUCT_KIND_CSTYLE_VARIANT:
+ return RustCStyleEnumPrinter(val[get_field_at_index(val, 0)])
+
+ if struct_kind == STRUCT_KIND_TUPLE_VARIANT:
+ return RustTupleStructPrinter(val, True)
+
+ if struct_kind == STRUCT_KIND_STRUCT_VARIANT:
+ return RustStructPrinter(val, True)
+
+ return RustStructPrinter(val, False)
+
+ # Enum handling
+ if type_code == gdb.TYPE_CODE_UNION:
+ enum_members = list(val.type.fields())
+ enum_member_count = len(enum_members)
+
+ if enum_member_count == 0:
+ return RustStructPrinter(val, false)
+
+ if enum_member_count == 1:
+ if enum_members[0].name == None:
+ # This is a singleton enum
+ return rust_pretty_printer_lookup_function(val[enum_members[0]])
+ else:
+ assert enum_members[0].name.startswith("RUST$ENCODED$ENUM$")
+ # This is a space-optimized enum
+ last_separator_index = enum_members[0].name.rfind("$")
+ second_last_separator_index = first_variant_name.rfind("$", 0, last_separator_index)
+ disr_field_index = first_variant_name[second_last_separator_index + 1 :
+ last_separator_index]
+ disr_field_index = int(disr_field_index)
+
+ sole_variant_val = val[enum_members[0]]
+ disr_field = get_field_at_index(sole_variant_val, disr_field_index)
+ discriminant = int(sole_variant_val[disr_field])
+
+ if discriminant == 0:
+ null_variant_name = first_variant_name[last_separator_index + 1:]
+ return IdentityPrinter(null_variant_name)
+
+ return rust_pretty_printer_lookup_function(sole_variant_val)
+
+ # This is a regular enum, extract the discriminant
+ discriminant_name, discriminant_val = extract_discriminant_value(val)
+ return rust_pretty_printer_lookup_function(val[enum_members[discriminant_val]])
+
+ # No pretty printer has been found
+ return None
+
+#=------------------------------------------------------------------------------
+# Pretty Printer Classes
+#=------------------------------------------------------------------------------
+
+class RustStructPrinter:
+ def __init__(self, val, hide_first_field):
+ self.val = val
+ self.hide_first_field = hide_first_field
+
+ def to_string(self):
+ return self.val.type.tag
+
+ def children(self):
+ cs = []
+ for field in self.val.type.fields():
+ field_name = field.name
+ # Normally the field name is used as a key to access the field value,
+ # because that's also supported in older versions of GDB...
+ field_key = field_name
+ if field_name == None:
+ field_name = ""
+ # ... but for fields without a name (as in tuples), we have to fall back
+ # to the newer method of using the field object directly as key. In
+ # older versions of GDB, this will just fail.
+ field_key = field
+ name_value_tuple = ( field_name, self.val[field_key] )
+ cs.append( name_value_tuple )
+
+ if self.hide_first_field:
+ cs = cs[1:]
+
+ return cs
+
+class RustTuplePrinter:
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ return None
+
+ def children(self):
+ cs = []
+ for field in self.val.type.fields():
+ cs.append( ("", self.val[field]) )
+
+ return cs
+
+ def display_hint(self):
+ return "array"
+
+class RustTupleStructPrinter:
+ def __init__(self, val, hide_first_field):
+ self.val = val
+ self.hide_first_field = hide_first_field
+
+ def to_string(self):
+ return self.val.type.tag
+
+ def children(self):
+ cs = []
+ for field in self.val.type.fields():
+ cs.append( ("", self.val[field]) )
+
+ if self.hide_first_field:
+ cs = cs[1:]
+
+ return cs
+
+ def display_hint(self):
+ return "array"
+
+class RustStringSlicePrinter:
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ slice_byte_len = self.val["length"]
+ return '"%s"' % self.val["data_ptr"].string(encoding = "utf-8",
+ length = slice_byte_len)
+
+class RustCStyleEnumPrinter:
+ def __init__(self, val):
+ assert val.type.code == gdb.TYPE_CODE_ENUM
+ self.val = val
+
+ def to_string(self):
+ return str(self.val)
+
+class IdentityPrinter:
+ def __init__(self, string):
+ self.string
+
+ def to_string(self):
+ return self.string
+
+STRUCT_KIND_REGULAR_STRUCT = 0
+STRUCT_KIND_TUPLE_STRUCT = 1
+STRUCT_KIND_TUPLE = 2
+STRUCT_KIND_TUPLE_VARIANT = 3
+STRUCT_KIND_STRUCT_VARIANT = 4
+STRUCT_KIND_CSTYLE_VARIANT = 5
+STRUCT_KIND_STR_SLICE = 6
+
+def classify_struct(type):
+ if type.tag == "&str":
+ return STRUCT_KIND_STR_SLICE
+
+ fields = list(type.fields())
+ field_count = len(fields)
+
+ if field_count == 0:
+ return STRUCT_KIND_REGULAR_STRUCT
+
+ if fields[0].artificial:
+ if field_count == 1:
+ return STRUCT_KIND_CSTYLE_VARIANT
+ elif fields[1].name == None:
+ return STRUCT_KIND_TUPLE_VARIANT
+ else:
+ return STRUCT_KIND_STRUCT_VARIANT
+
+ if fields[0].name == None:
+ if type.tag.startswith("("):
+ return STRUCT_KIND_TUPLE
+ else:
+ return STRUCT_KIND_TUPLE_STRUCT
+
+ return STRUCT_KIND_REGULAR_STRUCT
+
+def extract_discriminant_value(enum_val):
+ assert enum_val.type.code == gdb.TYPE_CODE_UNION
+ for variant_descriptor in enum_val.type.fields():
+ variant_val = enum_val[variant_descriptor]
+ for field in variant_val.type.fields():
+ return (field.name, int(variant_val[field]))
+
+def first_field(val):
+ for field in val.type.fields():
+ return field
+
+def get_field_at_index(val, index):
+ i = 0
+ for field in val.type.fields():
+ if i == index:
+ return field
+ return None
// NOTE: The following code was generated by "src/etc/unicode.py", do not edit directly
-#![allow(missing_doc, non_uppercase_statics, non_snake_case_functions)]
+#![allow(missing_doc, non_uppercase_statics, non_snake_case)]
'''
# Mapping taken from Table 12 from:
//!
//! This is the lowest level library through which allocation in Rust can be
//! performed where the allocation is assumed to succeed. This library will
-//! trigger a task failure when allocation fails.
+//! abort the process when allocation fails.
//!
//! This library, like libcore, is not intended for general usage, but rather as
//! a building block of other libraries. The types and interfaces in this
value: T,
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct Items<'a, T> {
- head: &'a Link<T>,
- tail: Rawlink<Node<T>>,
- nelem: uint,
-}
-
/// An iterator over references to the items of a `DList`.
-#[cfg(not(stage0))]
pub struct Items<'a, T:'a> {
head: &'a Link<T>,
tail: Rawlink<Node<T>>,
fn clone(&self) -> Items<'a, T> { *self }
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct MutItems<'a, T> {
- list: &'a mut DList<T>,
- head: Rawlink<Node<T>>,
- tail: Rawlink<Node<T>>,
- nelem: uint,
-}
-
/// An iterator over mutable references to the items of a `DList`.
-#[cfg(not(stage0))]
pub struct MutItems<'a, T:'a> {
list: &'a mut DList<T>,
head: Rawlink<Node<T>>,
( $($name:ident)+) => (
impl<S: Writer, $($name: Hash<S>),*> Hash<S> for ($($name,)*) {
- #[allow(uppercase_variables)]
#[inline]
+ #[allow(non_snake_case)]
fn hash(&self, state: &mut S) {
match *self {
($(ref $name,)*) => {
#![feature(unsafe_destructor, import_shadowing)]
#![no_std]
-// NOTE(stage0, pcwalton): Remove after snapshot.
-#![allow(unknown_features)]
-
#[phase(plugin, link)] extern crate core;
extern crate unicode;
extern crate alloc;
}
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct Items <'a, T> {
- iter: slice::Items<'a, T>,
-}
-
/// `PriorityQueue` iterator.
-#[cfg(not(stage0))]
pub struct Items <'a, T:'a> {
iter: slice::Items<'a, T>,
}
}
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct Items<'a, T> {
- lo: uint,
- index: uint,
- rindex: uint,
- elts: &'a [Option<T>],
-}
-
/// `RingBuf` iterator.
-#[cfg(not(stage0))]
pub struct Items<'a, T:'a> {
lo: uint,
index: uint,
}
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct MutItems<'a, T> {
- remaining1: &'a mut [Option<T>],
- remaining2: &'a mut [Option<T>],
- nelts: uint,
-}
-
/// `RingBuf` mutable iterator.
-#[cfg(not(stage0))]
pub struct MutItems<'a, T:'a> {
remaining1: &'a mut [Option<T>],
remaining2: &'a mut [Option<T>],
}
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct Entries<'a, T> {
- front: uint,
- back: uint,
- iter: slice::Items<'a, Option<T>>
-}
-
/// Forward iterator over a map.
-#[cfg(not(stage0))]
pub struct Entries<'a, T:'a> {
front: uint,
back: uint,
iterator!(impl Entries -> (uint, &'a T), get_ref)
double_ended_iterator!(impl Entries -> (uint, &'a T), get_ref)
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct MutEntries<'a, T> {
- front: uint,
- back: uint,
- iter: slice::MutItems<'a, Option<T>>
-}
-
/// Forward iterator over the key-value pairs of a map, with the
/// values being mutable.
-#[cfg(not(stage0))]
pub struct MutEntries<'a, T:'a> {
front: uint,
back: uint,
}
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct Entries<'a, K, V> {
- stack: Vec<&'a TreeNode<K, V>>,
- // See the comment on MutEntries; this is just to allow
- // code-sharing (for this immutable-values iterator it *could* very
- // well be Option<&'a TreeNode<K,V>>).
- node: *const TreeNode<K, V>,
- remaining_min: uint,
- remaining_max: uint
-}
-
/// Lazy forward iterator over a map
-#[cfg(not(stage0))]
pub struct Entries<'a, K:'a, V:'a> {
stack: Vec<&'a TreeNode<K, V>>,
// See the comment on MutEntries; this is just to allow
remaining_max: uint
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct RevEntries<'a, K, V> {
- iter: Entries<'a, K, V>,
-}
-
/// Lazy backward iterator over a map
-#[cfg(not(stage0))]
pub struct RevEntries<'a, K:'a, V:'a> {
iter: Entries<'a, K, V>,
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct MutEntries<'a, K, V> {
- stack: Vec<&'a mut TreeNode<K, V>>,
- // Unfortunately, we require some unsafe-ness to get around the
- // fact that we would be storing a reference *into* one of the
- // nodes in the stack.
- //
- // As far as the compiler knows, this would let us invalidate the
- // reference by assigning a new value to this node's position in
- // its parent, which would cause this current one to be
- // deallocated so this reference would be invalid. (i.e. the
- // compilers complaints are 100% correct.)
- //
- // However, as far as you humans reading this code know (or are
- // about to know, if you haven't read far enough down yet), we are
- // only reading from the TreeNode.{left,right} fields. the only
- // thing that is ever mutated is the .value field (although any
- // actual mutation that happens is done externally, by the
- // iterator consumer). So, don't be so concerned, rustc, we've got
- // it under control.
- //
- // (This field can legitimately be null.)
- node: *mut TreeNode<K, V>,
- remaining_min: uint,
- remaining_max: uint
-}
-
/// Lazy forward iterator over a map that allows for the mutation of
/// the values.
-#[cfg(not(stage0))]
pub struct MutEntries<'a, K:'a, V:'a> {
stack: Vec<&'a mut TreeNode<K, V>>,
// Unfortunately, we require some unsafe-ness to get around the
remaining_max: uint
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct RevMutEntries<'a, K, V> {
- iter: MutEntries<'a, K, V>,
-}
-
/// Lazy backward iterator over a map
-#[cfg(not(stage0))]
pub struct RevMutEntries<'a, K:'a, V:'a> {
iter: MutEntries<'a, K, V>,
}
}
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct SetItems<'a, T> {
- iter: Entries<'a, T, ()>
-}
-
/// A lazy forward iterator over a set.
-#[cfg(not(stage0))]
pub struct SetItems<'a, T:'a> {
iter: Entries<'a, T, ()>
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct RevSetItems<'a, T> {
- iter: RevEntries<'a, T, ()>
-}
-
/// A lazy backward iterator over a set.
-#[cfg(not(stage0))]
pub struct RevSetItems<'a, T:'a> {
iter: RevEntries<'a, T, ()>
}
/// A lazy forward iterator over a set that consumes the set while iterating.
pub type MoveSetItems<T> = iter::Map<'static, (T, ()), T, MoveEntries<T, ()>>;
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct DifferenceItems<'a, T> {
- a: Peekable<&'a T, SetItems<'a, T>>,
- b: Peekable<&'a T, SetItems<'a, T>>,
-}
-
/// A lazy iterator producing elements in the set difference (in-order).
-#[cfg(not(stage0))]
pub struct DifferenceItems<'a, T:'a> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct SymDifferenceItems<'a, T> {
- a: Peekable<&'a T, SetItems<'a, T>>,
- b: Peekable<&'a T, SetItems<'a, T>>,
-}
-
/// A lazy iterator producing elements in the set symmetric difference (in-order).
-#[cfg(not(stage0))]
pub struct SymDifferenceItems<'a, T:'a> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct IntersectionItems<'a, T> {
- a: Peekable<&'a T, SetItems<'a, T>>,
- b: Peekable<&'a T, SetItems<'a, T>>,
-}
-
/// A lazy iterator producing elements in the set intersection (in-order).
-#[cfg(not(stage0))]
pub struct IntersectionItems<'a, T:'a> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct UnionItems<'a, T> {
- a: Peekable<&'a T, SetItems<'a, T>>,
- b: Peekable<&'a T, SetItems<'a, T>>,
-}
-
/// A lazy iterator producing elements in the set union (in-order).
-#[cfg(not(stage0))]
pub struct UnionItems<'a, T:'a> {
a: Peekable<&'a T, SetItems<'a, T>>,
b: Peekable<&'a T, SetItems<'a, T>>,
return ret;
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct Entries<'a, T> {
- stack: [slice::Items<'a, Child<T>>, .. NUM_CHUNKS],
- length: uint,
- remaining_min: uint,
- remaining_max: uint
-}
-
/// A forward iterator over a map.
-#[cfg(not(stage0))]
pub struct Entries<'a, T:'a> {
stack: [slice::Items<'a, Child<T>>, .. NUM_CHUNKS],
length: uint,
remaining_max: uint
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct MutEntries<'a, T> {
- stack: [slice::MutItems<'a, Child<T>>, .. NUM_CHUNKS],
- length: uint,
- remaining_min: uint,
- remaining_max: uint
-}
-
/// A forward iterator over the key-value pairs of a map, with the
/// values being mutable.
-#[cfg(not(stage0))]
pub struct MutEntries<'a, T:'a> {
stack: [slice::MutItems<'a, Child<T>>, .. NUM_CHUNKS],
length: uint,
/// Wraps a borrowed reference to a value in a `RefCell` box.
#[unstable]
-#[cfg(not(stage0))]
pub struct Ref<'b, T:'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_parent: &'b RefCell<T>
}
-/// Dox.
-#[unstable]
-#[cfg(stage0)]
-pub struct Ref<'b, T> {
- // FIXME #12808: strange name to try to avoid interfering with
- // field accesses of the contained type via Deref
- _parent: &'b RefCell<T>
-}
-
#[unsafe_destructor]
#[unstable]
impl<'b, T> Drop for Ref<'b, T> {
/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
#[unstable]
-#[cfg(not(stage0))]
pub struct RefMut<'b, T:'b> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_parent: &'b RefCell<T>
}
-/// Dox.
-#[unstable]
-#[cfg(stage0)]
-pub struct RefMut<'b, T> {
- // FIXME #12808: strange name to try to avoid interfering with
- // field accesses of the contained type via Deref
- _parent: &'b RefCell<T>
-}
-
#[unsafe_destructor]
#[unstable]
impl<'b, T> Drop for RefMut<'b, T> {
//!
//! For more details, see ::unicode::char (a.k.a. std::char)
-#![allow(non_snake_case_functions)]
+#![allow(non_snake_case)]
#![doc(primitive = "char")]
use mem::transmute;
try_fn(&mut *f.mutate, drop)
}
-#[cfg(not(stage0))]
struct Finallyalizer<'a,A:'a> {
mutate: &'a mut A,
dtor: |&mut A|: 'a
}
-#[cfg(stage0)]
-struct Finallyalizer<'a,A> {
- mutate: &'a mut A,
- dtor: |&mut A|: 'a
-}
-
#[unsafe_destructor]
impl<'a,A> Drop for Finallyalizer<'a,A> {
#[inline]
() => ();
( $($name:ident,)+ ) => (
impl<$($name:Show),*> Show for ($($name,)*) {
- #[allow(uppercase_variables, dead_assignment)]
+ #[allow(non_snake_case, dead_assignment)]
fn fmt(&self, f: &mut Formatter) -> Result {
try!(write!(f, "("));
let ($(ref $name,)*) = *self;
fn visit_char(&mut self) -> bool;
fn visit_estr_slice(&mut self) -> bool;
- // NOTE: remove after snapshot
- #[cfg(stage0)]
- fn visit_estr_fixed(&mut self, n: uint, sz: uint, align: uint) -> bool;
fn visit_box(&mut self, mtbl: uint, inner: *const TyDesc) -> bool;
fn visit_uniq(&mut self, mtbl: uint, inner: *const TyDesc) -> bool;
fn visit_rptr(&mut self, mtbl: uint, inner: *const TyDesc) -> bool;
fn visit_evec_slice(&mut self, mtbl: uint, inner: *const TyDesc) -> bool;
- // NOTE: remove after snapshot
- #[cfg(stage0)]
- fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
- mtbl: uint, inner: *const TyDesc) -> bool;
- #[cfg(not(stage0))]
fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
inner: *const TyDesc) -> bool;
/// A mutable reference to an iterator
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
-#[cfg(not(stage0))]
pub struct ByRef<'a, T:'a> {
iter: &'a mut T
}
-/// Dox
-#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
-#[cfg(stage0)]
-pub struct ByRef<'a, T> {
- iter: &'a mut T
-}
-
impl<'a, A, T: Iterator<A>+'a> Iterator<A> for ByRef<'a, T> {
#[inline]
fn next(&mut self) -> Option<A> { self.iter.next() }
#![no_std]
#![feature(globs, intrinsics, lang_items, macro_rules, managed_boxes, phase)]
-#![feature(simd, unsafe_destructor, issue_5723_bootstrap)]
+#![feature(simd, unsafe_destructor)]
#![deny(missing_doc)]
mod macros;
/// Computes the absolute value.
///
/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`.
+ ///
+ /// For signed integers, `::MIN` will be returned if the number is `::MIN`.
fn abs(&self) -> Self;
/// The positive difference of two numbers.
/// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// * `NaN` if the number is `NaN`
///
- /// For `int`:
+ /// For signed integers:
///
/// * `0` if the number is zero
/// * `1` if the number is positive
/// Computes the absolute value.
///
/// For `f32` and `f64`, `NaN` will be returned if the number is `NaN`
+///
+/// For signed integers, `::MIN` will be returned if the number is `::MIN`.
#[inline(always)]
pub fn abs<T: Signed>(value: T) -> T {
value.abs()
/// * `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// * `NaN` if the number is `NaN`
///
-/// For int:
+/// For signed integers:
///
/// * `0` if the number is zero
/// * `1` if the number is positive
FnMut<($($args,)*),Result>
for extern "Rust" fn($($args: $args,)*) -> Result {
#[rust_call_abi_hack]
- #[allow(uppercase_variables)]
+ #[allow(non_snake_case)]
fn call_mut(&mut self, args: ($($args,)*)) -> Result {
let ($($args,)*) = args;
(*self)($($args,)*)
///
/// This struct does not have a `Repr` implementation
/// because there is no way to refer to all trait objects generically.
-#[cfg(stage0)]
-pub struct TraitObject {
- pub vtable: *mut (),
- pub data: *mut (),
-}
-#[cfg(not(stage0))]
pub struct TraitObject {
pub data: *mut (),
pub vtable: *mut (),
// Extension traits
//
-/// Extension methods for vectors
+/// Extension methods for immutable slices.
#[unstable = "may merge with other traits; region parameter may disappear"]
pub trait ImmutableSlice<'a, T> {
- /**
- * Returns a slice of self spanning the interval [`start`, `end`).
- *
- * Fails when the slice (or part of it) is outside the bounds of self,
- * or when `start` > `end`.
- */
+ /// Returns a subslice spanning the interval [`start`, `end`).
+ ///
+ /// Fails when the end of the new slice lies beyond the end of the
+ /// original slice (i.e. when `end > self.len()`) or when `start > end`.
+ ///
+ /// Slicing with `start` equal to `end` yields an empty slice.
#[unstable]
fn slice(&self, start: uint, end: uint) -> &'a [T];
- /**
- * Returns a slice of self from `start` to the end of the vec.
- *
- * Fails when `start` points outside the bounds of self.
- */
+ /// Returns a subslice from `start` to the end of the slice.
+ ///
+ /// Fails when `start` is strictly greater than the length of the original slice.
+ ///
+ /// Slicing from `self.len()` yields an empty slice.
#[unstable]
fn slice_from(&self, start: uint) -> &'a [T];
- /**
- * Returns a slice of self from the start of the vec to `end`.
- *
- * Fails when `end` points outside the bounds of self.
- */
+ /// Returns a subslice from the start of the slice to `end`.
+ ///
+ /// Fails when `end` is strictly greater than the length of the original slice.
+ ///
+ /// Slicing to `0` yields an empty slice.
#[unstable]
fn slice_to(&self, end: uint) -> &'a [T];
/// Primarily intended for getting a &mut [T] from a [T, ..N].
fn as_mut_slice(self) -> &'a mut [T];
- /// Return a slice that points into another slice.
+ /// Returns a mutable subslice spanning the interval [`start`, `end`).
+ ///
+ /// Fails when the end of the new slice lies beyond the end of the
+ /// original slice (i.e. when `end > self.len()`) or when `start > end`.
+ ///
+ /// Slicing with `start` equal to `end` yields an empty slice.
fn mut_slice(self, start: uint, end: uint) -> &'a mut [T];
- /**
- * Returns a slice of self from `start` to the end of the vec.
- *
- * Fails when `start` points outside the bounds of self.
- */
+ /// Returns a mutable subslice from `start` to the end of the slice.
+ ///
+ /// Fails when `start` is strictly greater than the length of the original slice.
+ ///
+ /// Slicing from `self.len()` yields an empty slice.
fn mut_slice_from(self, start: uint) -> &'a mut [T];
- /**
- * Returns a slice of self from the start of the vec to `end`.
- *
- * Fails when `end` points outside the bounds of self.
- */
+ /// Returns a mutable subslice from the start of the slice to `end`.
+ ///
+ /// Fails when `end` is strictly greater than the length of the original slice.
+ ///
+ /// Slicing to `0` yields an empty slice.
fn mut_slice_to(self, end: uint) -> &'a mut [T];
/// Returns an iterator that allows modifying each value
/// An iterator over the slices of a vector separated by elements that
/// match a predicate function.
-#[cfg(not(stage0))]
#[experimental = "needs review"]
pub struct Splits<'a, T:'a> {
v: &'a [T],
finished: bool
}
-/// Dox.
-#[cfg(stage0)]
-pub struct Splits<'a, T> {
- v: &'a [T],
- pred: |t: &T|: 'a -> bool,
- finished: bool
-}
-
#[experimental = "needs review"]
impl<'a, T> Iterator<&'a [T]> for Splits<'a, T> {
#[inline]
/// An iterator over the subslices of the vector which are separated
/// by elements that match `pred`.
-#[cfg(not(stage0))]
#[experimental = "needs review"]
pub struct MutSplits<'a, T:'a> {
v: &'a mut [T],
finished: bool
}
-/// Dox
-#[cfg(stage0)]
-pub struct MutSplits<'a, T> {
- v: &'a mut [T],
- pred: |t: &T|: 'a -> bool,
- finished: bool
-}
-
#[experimental = "needs review"]
impl<'a, T> Iterator<&'a mut [T]> for MutSplits<'a, T> {
#[inline]
/// An iterator over the slices of a vector separated by elements that
/// match a predicate function, splitting at most a fixed number of times.
-#[cfg(not(stage0))]
#[experimental = "needs review"]
pub struct SplitsN<'a, T:'a> {
iter: Splits<'a, T>,
invert: bool
}
-/// Dox.
-#[cfg(stage0)]
-pub struct SplitsN<'a, T> {
- iter: Splits<'a, T>,
- count: uint,
- invert: bool
-}
-
#[experimental = "needs review"]
impl<'a, T> Iterator<&'a [T]> for SplitsN<'a, T> {
#[inline]
/// An iterator over the (overlapping) slices of length `size` within
/// a vector.
-#[cfg(stage0)]
-#[deriving(Clone)]
-#[experimental = "needs review"]
-pub struct Windows<'a, T> {
- v: &'a [T],
- size: uint
-}
-
-/// An iterator over the (overlapping) slices of length `size` within
-/// a vector.
-#[cfg(not(stage0))]
#[deriving(Clone)]
#[experimental = "needs review"]
pub struct Windows<'a, T:'a> {
///
/// When the vector len is not evenly divided by the chunk size,
/// the last slice of the iteration will be the remainder.
-#[cfg(stage0)]
#[deriving(Clone)]
#[experimental = "needs review"]
-pub struct Chunks<'a, T> {
- v: &'a [T],
- size: uint
-}
-
-/// An iterator over a vector in (non-overlapping) chunks (`size`
-/// elements at a time).
-///
-/// When the vector len is not evenly divided by the chunk size,
-/// the last slice of the iteration will be the remainder.
-#[cfg(not(stage0))]
-#[deriving(Clone)]
pub struct Chunks<'a, T:'a> {
v: &'a [T],
size: uint
/// An iterator over a vector in (non-overlapping) mutable chunks (`size` elements at a time). When
/// the vector len is not evenly divided by the chunk size, the last slice of the iteration will be
/// the remainder.
-#[cfg(not(stage0))]
#[experimental = "needs review"]
pub struct MutChunks<'a, T:'a> {
v: &'a mut [T],
chunk_size: uint
}
-/// Dox.
-#[cfg(stage0)]
-pub struct MutChunks<'a, T> {
- v: &'a mut [T],
- chunk_size: uint
-}
-
#[experimental = "needs review"]
impl<'a, T> Iterator<&'a mut [T]> for MutChunks<'a, T> {
#[inline]
fn next(&mut self, haystack: &[u8], needle: &[u8]) -> Option<(uint, uint)> {
while self.position + needle.len() <= haystack.len() {
if haystack.slice(self.position, self.position + needle.len()) == needle {
- let matchPos = self.position;
+ let match_pos = self.position;
self.position += needle.len(); // add 1 for all matches
- return Some((matchPos, matchPos + needle.len()));
+ return Some((match_pos, match_pos + needle.len()));
} else {
self.position += 1;
}
#[deriving(Clone)]
struct TwoWaySearcher {
// constants
- critPos: uint,
+ crit_pos: uint,
period: uint,
byteset: u64,
// Crochemore, M., Perrin, D., 1991, Two-way string-matching, Journal of the ACM 38(3):651-675.
impl TwoWaySearcher {
fn new(needle: &[u8]) -> TwoWaySearcher {
- let (critPos1, period1) = TwoWaySearcher::maximal_suffix(needle, false);
- let (critPos2, period2) = TwoWaySearcher::maximal_suffix(needle, true);
+ let (crit_pos1, period1) = TwoWaySearcher::maximal_suffix(needle, false);
+ let (crit_pos2, period2) = TwoWaySearcher::maximal_suffix(needle, true);
- let critPos;
+ let crit_pos;
let period;
- if critPos1 > critPos2 {
- critPos = critPos1;
+ if crit_pos1 > crit_pos2 {
+ crit_pos = crit_pos1;
period = period1;
} else {
- critPos = critPos2;
+ crit_pos = crit_pos2;
period = period2;
}
let byteset = needle.iter()
.fold(0, |a, &b| (1 << ((b & 0x3f) as uint)) | a);
-
- // The logic here (calculating critPos and period, the final if statement to see which
+ // The logic here (calculating crit_pos and period, the final if statement to see which
// period to use for the TwoWaySearcher) is essentially an implementation of the
// "small-period" function from the paper (p. 670)
//
- // In the paper they check whether `needle.slice_to(critPos)` is a suffix of
- // `needle.slice(critPos, critPos + period)`, which is precisely what this does
- if needle.slice_to(critPos) == needle.slice(period, period + critPos) {
+ // In the paper they check whether `needle.slice_to(crit_pos)` is a suffix of
+ // `needle.slice(crit_pos, crit_pos + period)`, which is precisely what this does
+ if needle.slice_to(crit_pos) == needle.slice(period, period + crit_pos) {
TwoWaySearcher {
- critPos: critPos,
+ crit_pos: crit_pos,
period: period,
byteset: byteset,
}
} else {
TwoWaySearcher {
- critPos: critPos,
- period: cmp::max(critPos, needle.len() - critPos) + 1,
+ crit_pos: crit_pos,
+ period: cmp::max(crit_pos, needle.len() - crit_pos) + 1,
byteset: byteset,
position: 0,
}
#[inline]
- fn next(&mut self, haystack: &[u8], needle: &[u8], longPeriod: bool) -> Option<(uint, uint)> {
+ fn next(&mut self, haystack: &[u8], needle: &[u8], long_period: bool) -> Option<(uint, uint)> {
'search: loop {
// Check that we have room to search in
if self.position + needle.len() > haystack.len() {
}
// See if the right part of the needle matches
- let start = if longPeriod { self.critPos } else { cmp::max(self.critPos, self.memory) };
+ let start = if long_period { self.crit_pos }
+ else { cmp::max(self.crit_pos, self.memory) };
for i in range(start, needle.len()) {
if needle[i] != haystack[self.position + i] {
- self.position += i - self.critPos + 1;
- if !longPeriod {
+ self.position += i - self.crit_pos + 1;
+ if !long_period {
self.memory = 0;
}
continue 'search;
}
// See if the left part of the needle matches
- let start = if longPeriod { 0 } else { self.memory };
- for i in range(start, self.critPos).rev() {
+ let start = if long_period { 0 } else { self.memory };
+ for i in range(start, self.crit_pos).rev() {
if needle[i] != haystack[self.position + i] {
self.position += self.period;
- if !longPeriod {
+ if !long_period {
self.memory = needle.len() - self.period;
}
continue 'search;
}
// We have found a match!
- let matchPos = self.position;
+ let match_pos = self.position;
self.position += needle.len(); // add self.period for all matches
- if !longPeriod {
+ if !long_period {
self.memory = 0; // set to needle.len() - self.period for all matches
}
- return Some((matchPos, matchPos + needle.len()));
+ return Some((match_pos, match_pos + needle.len()));
}
}
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/master/")]
#![experimental]
-#![feature(managed_boxes, macro_rules, issue_5723_bootstrap)]
+#![feature(managed_boxes, macro_rules)]
#![allow(experimental)]
pub mod fmt;
true
}
- // NOTE: remove after snapshot
- #[cfg(stage0)]
- fn visit_estr_fixed(&mut self, n: uint,
- sz: uint,
- align: uint) -> bool {
- self.align(align);
- if ! self.inner.visit_estr_fixed(n, sz, align) { return false; }
- self.bump(sz);
- true
- }
-
fn visit_box(&mut self, mtbl: uint, inner: *const TyDesc) -> bool {
self.align_to::<Gc<u8>>();
if ! self.inner.visit_box(mtbl, inner) { return false; }
true
}
- #[cfg(stage0)]
- fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
- mtbl: uint, inner: *const TyDesc) -> bool {
- self.align(align);
- if ! self.inner.visit_evec_fixed(n, sz, align, mtbl, inner) {
- return false;
- }
- self.bump(sz);
- true
- }
- #[cfg(not(stage0))]
fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
inner: *const TyDesc) -> bool {
self.align(align);
self.get::<&str>(|this, s| this.write_escaped_slice(*s))
}
- // Type no longer exists, vestigial function.
- // NOTE: remove after snapshot
- #[cfg(stage0)]
- fn visit_estr_fixed(&mut self, _n: uint, _sz: uint,
- _align: uint) -> bool { fail!(); }
-
fn visit_box(&mut self, mtbl: uint, inner: *const TyDesc) -> bool {
try!(self, self.writer.write("box(GC) ".as_bytes()));
self.write_mut_qualifier(mtbl);
})
}
- // NOTE: remove after snapshot
- #[cfg(stage0)]
- fn visit_evec_fixed(&mut self, n: uint, sz: uint, _align: uint,
- _: uint, inner: *const TyDesc) -> bool {
- let assumed_size = if sz == 0 { n } else { sz };
- self.get::<()>(|this, b| {
- this.write_vec_range(b, assumed_size, inner)
- })
- }
-
- #[cfg(not(stage0))]
fn visit_evec_fixed(&mut self, n: uint, sz: uint, _align: uint,
inner: *const TyDesc) -> bool {
let assumed_size = if sz == 0 { n } else { sz };
#![crate_type = "dylib"]
#![feature(macro_rules, globs, import_shadowing)]
-// NOTE(stage0, pcwalton): Remove after snapshot.
-#![allow(unknown_features)]
-
use std::char;
use std::str;
#![feature(import_shadowing)]
#![deny(missing_doc)]
-// NOTE(stage0, pcwalton): Remove after snapshot.
-#![allow(unknown_features)]
-
#[cfg(test)] extern crate debug;
#[cfg(test)] #[phase(plugin, link)] extern crate log;
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
-#![feature(issue_5723_bootstrap)]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/master/")]
/// Some clients will have a pre-allocated vector ready to hand off in
/// a slice; others will want to create the set on the fly and hand
/// off ownership, via `Growable`.
-#[cfg(not(stage0))]
pub enum MaybeOwnedVector<'a,T:'a> {
Growable(Vec<T>),
Borrowed(&'a [T]),
}
-/// Stage0 only.
-#[cfg(stage0)]
-pub enum MaybeOwnedVector<'a,T> {
- Growable(Vec<T>),
- Borrowed(&'a [T]),
-}
-
/// Trait for moving into a `MaybeOwnedVector`
pub trait IntoMaybeOwnedVector<'a,T> {
/// Moves self into a `MaybeOwnedVector`
*/
#![allow(non_camel_case_types)]
-#![allow(non_snake_case_functions)]
+#![allow(non_snake_case)]
#![allow(non_uppercase_statics)]
#![allow(missing_doc)]
-#![allow(uppercase_variables)]
+#![allow(non_snake_case)]
#[cfg(test)] extern crate std;
#[cfg(test)] extern crate test;
//! play. The only dependencies of these modules are the normal system libraries
//! that you would find on the respective platform.
-#![allow(non_snake_case_functions)]
+#![allow(non_snake_case)]
use libc::c_int;
use libc;
#[cfg(unix)]
fn translate_status(status: c_int) -> rtio::ProcessExit {
- #![allow(non_snake_case_functions)]
+ #![allow(non_snake_case)]
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
mod imp {
pub static ZERO_BIG_DIGIT: BigDigit = 0;
static ZERO_VEC: [BigDigit, ..1] = [ZERO_BIG_DIGIT];
+#[allow(non_snake_case)]
pub mod BigDigit {
use super::BigDigit;
use super::DoubleBigDigit;
}
/// Rounds to the nearest integer. Rounds half-way cases away from zero.
- ///
- /// Note: This function is currently broken and always rounds away from zero.
#[inline]
pub fn round(&self) -> Ratio<T> {
- // FIXME(#15826)
if *self < Zero::zero() {
- Ratio::from_integer((self.numer - self.denom + One::one()) / self.denom)
+ // a/b - 1/2 = (2*a - b)/(2*b)
+ Ratio::from_integer((self.numer + self.numer - self.denom) / (self.denom + self.denom))
} else {
- Ratio::from_integer((self.numer + self.denom - One::one()) / self.denom)
+ // a/b + 1/2 = (2*a + b)/(2*b)
+ Ratio::from_integer((self.numer + self.numer + self.denom) / (self.denom + self.denom))
}
}
pub static _2: Rational = Ratio { numer: 2, denom: 1};
pub static _1_2: Rational = Ratio { numer: 1, denom: 2};
pub static _3_2: Rational = Ratio { numer: 3, denom: 2};
- pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2};
+ pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2};
+ pub static _1_3: Rational = Ratio { numer: 1, denom: 3};
+ pub static _neg1_3: Rational = Ratio { numer: -1, denom: 3};
+ pub static _2_3: Rational = Ratio { numer: 2, denom: 3};
+ pub static _neg2_3: Rational = Ratio { numer: -2, denom: 3};
pub fn to_big(n: Rational) -> BigRational {
Ratio::new(
#[test]
fn test_round() {
+ assert_eq!(_1_3.ceil(), _1);
+ assert_eq!(_1_3.floor(), _0);
+ assert_eq!(_1_3.round(), _0);
+ assert_eq!(_1_3.trunc(), _0);
+
+ assert_eq!(_neg1_3.ceil(), _0);
+ assert_eq!(_neg1_3.floor(), -_1);
+ assert_eq!(_neg1_3.round(), _0);
+ assert_eq!(_neg1_3.trunc(), _0);
+
+ assert_eq!(_2_3.ceil(), _1);
+ assert_eq!(_2_3.floor(), _0);
+ assert_eq!(_2_3.round(), _1);
+ assert_eq!(_2_3.trunc(), _0);
+
+ assert_eq!(_neg2_3.ceil(), _0);
+ assert_eq!(_neg2_3.floor(), -_1);
+ assert_eq!(_neg2_3.round(), -_1);
+ assert_eq!(_neg2_3.trunc(), _0);
+
assert_eq!(_1_2.ceil(), _1);
assert_eq!(_1_2.floor(), _0);
assert_eq!(_1_2.round(), _1);
pub item: T,
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct WeightedChoice<'a, T> {
- items: &'a mut [Weighted<T>],
- weight_range: Range<uint>
-}
-
/// A distribution that selects from a finite collection of weighted items.
///
/// Each item has an associated weight that influences how likely it
/// println!("{}", wc.ind_sample(&mut rng));
/// }
/// ```
-#[cfg(not(stage0))]
pub struct WeightedChoice<'a, T:'a> {
items: &'a mut [Weighted<T>],
weight_range: Range<uint>
}
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct Generator<'a, T, R> {
- rng: &'a mut R,
-}
-
/// Iterator which will generate a stream of random items.
///
/// This iterator is created via the `gen_iter` method on `Rng`.
-#[cfg(not(stage0))]
pub struct Generator<'a, T, R:'a> {
rng: &'a mut R,
}
}
}
-/// Note: stage0-specific version.
-#[cfg(stage0)]
-pub struct AsciiGenerator<'a, R> {
- rng: &'a mut R,
-}
-
/// Iterator which will continuously generate random ascii characters.
///
/// This iterator is created via the `gen_ascii_chars` method on `Rng`.
-#[cfg(not(stage0))]
pub struct AsciiGenerator<'a, R:'a> {
rng: &'a mut R,
}
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
-#![feature(macro_rules, phase, issue_5723_bootstrap)]
+#![feature(macro_rules, phase)]
#![allow(missing_doc)]
extern crate serialize;
pub type EncodeResult = io::IoResult<()>;
// rbml writing
- #[cfg(stage0)]
- pub struct Encoder<'a, W> {
- pub writer: &'a mut W,
- size_positions: Vec<uint>,
- }
-
- // rbml writing
- #[cfg(not(stage0))]
pub struct Encoder<'a, W:'a> {
pub writer: &'a mut W,
size_positions: Vec<uint>,
#[cfg(test)]
mod bench {
- #![allow(non_snake_case_functions)]
+ #![allow(non_snake_case)]
use test::Bencher;
use super::reader;
// <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.
-#![allow(non_snake_case_functions)]
+#![allow(non_snake_case)]
use std::rand::{Rng, task_rng};
use stdtest::Bencher;
// LLVM to optimize these function calls to themselves!
#![no_builtins]
-// NOTE(stage0, pcwalton): Remove after snapshot.
-#![allow(unknown_features)]
-
#[cfg(test)] extern crate native;
#[cfg(test)] extern crate test;
#[cfg(test)] extern crate debug;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_snake_case)]
+
register_diagnostic!(E0001, r##"
This error suggests that the expression arm corresponding to the noted pattern
will never be reached as for all possible values of the expression being matched,
use back::link;
use driver::session::Session;
-use driver::{config, PpMode, PpSourceMode};
-use driver::{PpmFlowGraph, PpmExpanded, PpmExpandedIdentified, PpmTyped};
-use driver::{PpmIdentified, PpmNormal, PpmSource};
+use driver::config;
use front;
use lint;
use llvm::{ContextRef, ModuleRef};
use metadata::common::LinkMeta;
use metadata::creader;
-use middle::borrowck::{FnPartsWithCFG};
-use middle::borrowck;
-use middle::borrowck::graphviz as borrowck_dot;
-use middle::cfg;
-use middle::cfg::graphviz::LabelledCFG;
use middle::{trans, freevars, stability, kind, ty, typeck, reachable};
use middle::dependency_format;
use middle;
use plugin;
use util::common::time;
-use util::ppaux;
use util::nodemap::{NodeSet};
-use graphviz as dot;
-
use serialize::{json, Encodable};
-use std::from_str::FromStr;
use std::io;
use std::io::fs;
-use std::io::MemReader;
-use std::option;
use syntax::ast;
-use syntax::ast_map;
-use syntax::ast_map::blocks;
-use syntax::ast_map::NodePrinter;
use syntax::attr;
use syntax::attr::{AttrMetaMethods};
use syntax::diagnostics;
use syntax::parse;
use syntax::parse::token;
-use syntax::print::{pp, pprust};
use syntax;
pub fn host_triple() -> &'static str {
}
});
- let Registry { syntax_exts, lint_passes, .. } = registry;
+ let Registry { syntax_exts, lint_passes, lint_groups, .. } = registry;
{
let mut ls = sess.lint_store.borrow_mut();
for pass in lint_passes.move_iter() {
ls.register_pass(Some(sess), true, pass);
}
+
+ for (name, to) in lint_groups.move_iter() {
+ ls.register_group(Some(sess), true, name, to);
+ }
}
// Lint plugins are registered; now we can process command line flags.
}
}
-// This slightly awkward construction is to allow for each PpMode to
-// choose whether it needs to do analyses (which can consume the
-// Session) and then pass through the session (now attached to the
-// analysis results) on to the chosen pretty-printer, along with the
-// `&PpAnn` object.
-//
-// Note that since the `&PrinterSupport` is freshly constructed on each
-// call, it would not make sense to try to attach the lifetime of `self`
-// to the lifetime of the `&PrinterObject`.
-//
-// (The `use_once_payload` is working around the current lack of once
-// functions in the compiler.)
-trait CratePrinter {
- /// Constructs a `PrinterSupport` object and passes it to `f`.
- fn call_with_pp_support<A,B>(&self,
- sess: Session,
- krate: &ast::Crate,
- ast_map: Option<syntax::ast_map::Map>,
- id: String,
- use_once_payload: B,
- f: |&PrinterSupport, B| -> A) -> A;
-}
-
-trait SessionCarrier {
- /// Provides a uniform interface for re-extracting a reference to a
- /// `Session` from a value that now owns it.
- fn sess<'a>(&'a self) -> &'a Session;
-}
-
-trait AstMapCarrier {
- /// Provides a uniform interface for re-extracting a reference to an
- /// `ast_map::Map` from a value that now owns it.
- fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map>;
-}
-
-trait PrinterSupport : SessionCarrier + AstMapCarrier {
- /// Produces the pretty-print annotation object.
- ///
- /// Usually implemented via `self as &pprust::PpAnn`.
- ///
- /// (Rust does not yet support upcasting from a trait object to
- /// an object for one of its super-traits.)
- fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn;
-}
-
-struct NoAnn {
- sess: Session,
- ast_map: Option<ast_map::Map>,
-}
-
-impl PrinterSupport for NoAnn {
- fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self as &pprust::PpAnn }
-}
-
-impl SessionCarrier for NoAnn {
- fn sess<'a>(&'a self) -> &'a Session { &self.sess }
-}
-
-impl AstMapCarrier for NoAnn {
- fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map> {
- self.ast_map.as_ref()
- }
-}
-
-impl pprust::PpAnn for NoAnn {}
-
-struct IdentifiedAnnotation {
- sess: Session,
- ast_map: Option<ast_map::Map>,
-}
-
-impl PrinterSupport for IdentifiedAnnotation {
- fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self as &pprust::PpAnn }
-}
-
-impl SessionCarrier for IdentifiedAnnotation {
- fn sess<'a>(&'a self) -> &'a Session { &self.sess }
-}
-
-impl AstMapCarrier for IdentifiedAnnotation {
- fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map> {
- self.ast_map.as_ref()
- }
-}
-
-impl pprust::PpAnn for IdentifiedAnnotation {
- fn pre(&self,
- s: &mut pprust::State,
- node: pprust::AnnNode) -> io::IoResult<()> {
- match node {
- pprust::NodeExpr(_) => s.popen(),
- _ => Ok(())
- }
- }
- fn post(&self,
- s: &mut pprust::State,
- node: pprust::AnnNode) -> io::IoResult<()> {
- match node {
- pprust::NodeItem(item) => {
- try!(pp::space(&mut s.s));
- s.synth_comment(item.id.to_string())
- }
- pprust::NodeBlock(blk) => {
- try!(pp::space(&mut s.s));
- s.synth_comment(format!("block {}", blk.id))
- }
- pprust::NodeExpr(expr) => {
- try!(pp::space(&mut s.s));
- try!(s.synth_comment(expr.id.to_string()));
- s.pclose()
- }
- pprust::NodePat(pat) => {
- try!(pp::space(&mut s.s));
- s.synth_comment(format!("pat {}", pat.id))
- }
- }
- }
-}
-
-struct TypedAnnotation {
- analysis: CrateAnalysis,
-}
-
-impl PrinterSupport for TypedAnnotation {
- fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self as &pprust::PpAnn }
-}
-
-impl SessionCarrier for TypedAnnotation {
- fn sess<'a>(&'a self) -> &'a Session { &self.analysis.ty_cx.sess }
-}
-
-impl AstMapCarrier for TypedAnnotation {
- fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map> {
- Some(&self.analysis.ty_cx.map)
- }
-}
-
-impl pprust::PpAnn for TypedAnnotation {
- fn pre(&self,
- s: &mut pprust::State,
- node: pprust::AnnNode) -> io::IoResult<()> {
- match node {
- pprust::NodeExpr(_) => s.popen(),
- _ => Ok(())
- }
- }
- fn post(&self,
- s: &mut pprust::State,
- node: pprust::AnnNode) -> io::IoResult<()> {
- let tcx = &self.analysis.ty_cx;
- match node {
- pprust::NodeExpr(expr) => {
- try!(pp::space(&mut s.s));
- try!(pp::word(&mut s.s, "as"));
- try!(pp::space(&mut s.s));
- try!(pp::word(&mut s.s,
- ppaux::ty_to_string(
- tcx,
- ty::expr_ty(tcx, expr)).as_slice()));
- s.pclose()
- }
- _ => Ok(())
- }
- }
-}
-
-fn gather_flowgraph_variants(sess: &Session) -> Vec<borrowck_dot::Variant> {
- let print_loans = config::FLOWGRAPH_PRINT_LOANS;
- let print_moves = config::FLOWGRAPH_PRINT_MOVES;
- let print_assigns = config::FLOWGRAPH_PRINT_ASSIGNS;
- let print_all = config::FLOWGRAPH_PRINT_ALL;
- let opt = |print_which| sess.debugging_opt(print_which);
- let mut variants = Vec::new();
- if opt(print_all) || opt(print_loans) {
- variants.push(borrowck_dot::Loans);
- }
- if opt(print_all) || opt(print_moves) {
- variants.push(borrowck_dot::Moves);
- }
- if opt(print_all) || opt(print_assigns) {
- variants.push(borrowck_dot::Assigns);
- }
- variants
-}
-
-#[deriving(Clone, Show)]
-pub enum UserIdentifiedItem {
- ItemViaNode(ast::NodeId),
- ItemViaPath(Vec<String>),
-}
-
-impl FromStr for UserIdentifiedItem {
- fn from_str(s: &str) -> Option<UserIdentifiedItem> {
- let extract_path_parts = || {
- let v : Vec<_> = s.split_str("::")
- .map(|x|x.to_string())
- .collect();
- Some(ItemViaPath(v))
- };
-
- from_str(s).map(ItemViaNode).or_else(extract_path_parts)
- }
-}
-
-enum NodesMatchingUII<'a> {
- NodesMatchingDirect(option::Item<ast::NodeId>),
- NodesMatchingSuffix(ast_map::NodesMatchingSuffix<'a, String>),
-}
-
-impl<'a> Iterator<ast::NodeId> for NodesMatchingUII<'a> {
- fn next(&mut self) -> Option<ast::NodeId> {
- match self {
- &NodesMatchingDirect(ref mut iter) => iter.next(),
- &NodesMatchingSuffix(ref mut iter) => iter.next(),
- }
- }
-}
-
-impl UserIdentifiedItem {
- fn reconstructed_input(&self) -> String {
- match *self {
- ItemViaNode(node_id) => node_id.to_string(),
- ItemViaPath(ref parts) => parts.connect("::"),
- }
- }
-
- fn all_matching_node_ids<'a>(&'a self, map: &'a ast_map::Map) -> NodesMatchingUII<'a> {
- match *self {
- ItemViaNode(node_id) =>
- NodesMatchingDirect(Some(node_id).move_iter()),
- ItemViaPath(ref parts) =>
- NodesMatchingSuffix(map.nodes_matching_suffix(parts.as_slice())),
- }
- }
-
- fn to_one_node_id(self, user_option: &str, sess: &Session, map: &ast_map::Map) -> ast::NodeId {
- let fail_because = |is_wrong_because| -> ast::NodeId {
- let message =
- format!("{:s} needs NodeId (int) or unique \
- path suffix (b::c::d); got {:s}, which {:s}",
- user_option,
- self.reconstructed_input(),
- is_wrong_because);
- sess.fatal(message.as_slice())
- };
-
- let mut saw_node = ast::DUMMY_NODE_ID;
- let mut seen = 0u;
- for node in self.all_matching_node_ids(map) {
- saw_node = node;
- seen += 1;
- if seen > 1 {
- fail_because("does not resolve uniquely");
- }
- }
- if seen == 0 {
- fail_because("does not resolve to any item");
- }
-
- assert!(seen == 1);
- return saw_node;
- }
-}
-
-impl CratePrinter for PpSourceMode {
- fn call_with_pp_support<A,B>(&self,
- sess: Session,
- krate: &ast::Crate,
- ast_map: Option<syntax::ast_map::Map>,
- id: String,
- payload: B,
- f: |&PrinterSupport, B| -> A) -> A {
- match *self {
- PpmNormal | PpmExpanded => {
- let annotation = NoAnn { sess: sess, ast_map: ast_map };
- f(&annotation, payload)
- }
-
- PpmIdentified | PpmExpandedIdentified => {
- let annotation = IdentifiedAnnotation { sess: sess, ast_map: ast_map };
- f(&annotation, payload)
- }
- PpmTyped => {
- let ast_map = ast_map.expect("--pretty=typed missing ast_map");
- let analysis = phase_3_run_analysis_passes(sess, krate, ast_map, id);
- let annotation = TypedAnnotation { analysis: analysis };
- f(&annotation, payload)
- }
- }
- }
-}
-
-fn needs_ast_map(ppm: &PpMode, opt_uii: &Option<UserIdentifiedItem>) -> bool {
- match *ppm {
- PpmSource(PpmNormal) |
- PpmSource(PpmIdentified) => opt_uii.is_some(),
-
- PpmSource(PpmExpanded) |
- PpmSource(PpmExpandedIdentified) |
- PpmSource(PpmTyped) |
- PpmFlowGraph => true
- }
-}
-
-fn needs_expansion(ppm: &PpMode) -> bool {
- match *ppm {
- PpmSource(PpmNormal) |
- PpmSource(PpmIdentified) => false,
-
- PpmSource(PpmExpanded) |
- PpmSource(PpmExpandedIdentified) |
- PpmSource(PpmTyped) |
- PpmFlowGraph => true
- }
-}
-pub fn pretty_print_input(sess: Session,
- cfg: ast::CrateConfig,
- input: &Input,
- ppm: PpMode,
- opt_uii: Option<UserIdentifiedItem>,
- ofile: Option<Path>) {
- let krate = phase_1_parse_input(&sess, cfg, input);
- let id = link::find_crate_name(Some(&sess), krate.attrs.as_slice(), input);
-
- let is_expanded = needs_expansion(&ppm);
- let (krate, ast_map) = if needs_ast_map(&ppm, &opt_uii) {
- let k = phase_2_configure_and_expand(&sess, krate, id.as_slice(), None);
- let (krate, ast_map) = match k {
- None => return,
- Some(p) => p,
- };
- (krate, Some(ast_map))
- } else {
- (krate, None)
- };
-
- let src_name = source_name(input);
- let src = Vec::from_slice(sess.codemap()
- .get_filemap(src_name.as_slice())
- .src
- .as_bytes());
- let mut rdr = MemReader::new(src);
-
- let out = match ofile {
- None => box io::stdout() as Box<Writer+'static>,
- Some(p) => {
- let r = io::File::create(&p);
- match r {
- Ok(w) => box w as Box<Writer+'static>,
- Err(e) => fail!("print-print failed to open {} due to {}",
- p.display(), e),
- }
- }
- };
-
- match (ppm, opt_uii) {
- (PpmSource(s), None) =>
- s.call_with_pp_support(
- sess, &krate, ast_map, id, out, |annotation, out| {
- debug!("pretty printing source code {}", s);
- let sess = annotation.sess();
- pprust::print_crate(sess.codemap(),
- sess.diagnostic(),
- &krate,
- src_name.to_string(),
- &mut rdr,
- out,
- annotation.pp_ann(),
- is_expanded)
- }),
-
- (PpmSource(s), Some(uii)) =>
- s.call_with_pp_support(
- sess, &krate, ast_map, id, (out,uii), |annotation, (out,uii)| {
- debug!("pretty printing source code {}", s);
- let sess = annotation.sess();
- let ast_map = annotation.ast_map()
- .expect("--pretty missing ast_map");
- let mut pp_state =
- pprust::State::new_from_input(sess.codemap(),
- sess.diagnostic(),
- src_name.to_string(),
- &mut rdr,
- out,
- annotation.pp_ann(),
- is_expanded);
- for node_id in uii.all_matching_node_ids(ast_map) {
- let node = ast_map.get(node_id);
- try!(pp_state.print_node(&node));
- try!(pp::space(&mut pp_state.s));
- try!(pp_state.synth_comment(ast_map.path_to_string(node_id)));
- try!(pp::hardbreak(&mut pp_state.s));
- }
- pp::eof(&mut pp_state.s)
- }),
-
- (PpmFlowGraph, opt_uii) => {
- debug!("pretty printing flow graph for {}", opt_uii);
- let uii = opt_uii.unwrap_or_else(|| {
- sess.fatal(format!("`pretty flowgraph=..` needs NodeId (int) or
- unique path suffix (b::c::d)").as_slice())
-
- });
- let ast_map = ast_map.expect("--pretty flowgraph missing ast_map");
- let nodeid = uii.to_one_node_id("--pretty", &sess, &ast_map);
-
- let node = ast_map.find(nodeid).unwrap_or_else(|| {
- sess.fatal(format!("--pretty flowgraph couldn't find id: {}",
- nodeid).as_slice())
- });
-
- let code = blocks::Code::from_node(node);
- match code {
- Some(code) => {
- let variants = gather_flowgraph_variants(&sess);
- let analysis = phase_3_run_analysis_passes(sess, &krate,
- ast_map, id);
- print_flowgraph(variants, analysis, code, out)
- }
- None => {
- let message = format!("--pretty=flowgraph needs \
- block, fn, or method; got {:?}",
- node);
-
- // point to what was found, if there's an
- // accessible span.
- match ast_map.opt_span(nodeid) {
- Some(sp) => sess.span_fatal(sp, message.as_slice()),
- None => sess.fatal(message.as_slice())
- }
- }
- }
- }
- }.unwrap()
-}
-
-fn print_flowgraph<W:io::Writer>(variants: Vec<borrowck_dot::Variant>,
- analysis: CrateAnalysis,
- code: blocks::Code,
- mut out: W) -> io::IoResult<()> {
- let ty_cx = &analysis.ty_cx;
- let cfg = match code {
- blocks::BlockCode(block) => cfg::CFG::new(ty_cx, &*block),
- blocks::FnLikeCode(fn_like) => cfg::CFG::new(ty_cx, &*fn_like.body()),
- };
- debug!("cfg: {:?}", cfg);
-
- match code {
- _ if variants.len() == 0 => {
- let lcfg = LabelledCFG {
- ast_map: &ty_cx.map,
- cfg: &cfg,
- name: format!("node_{}", code.id()),
- };
- let r = dot::render(&lcfg, &mut out);
- return expand_err_details(r);
- }
- blocks::BlockCode(_) => {
- ty_cx.sess.err("--pretty flowgraph with -Z flowgraph-print \
- annotations requires fn-like node id.");
- return Ok(())
- }
- blocks::FnLikeCode(fn_like) => {
- let fn_parts = FnPartsWithCFG::from_fn_like(&fn_like, &cfg);
- let (bccx, analysis_data) =
- borrowck::build_borrowck_dataflow_data_for_fn(ty_cx, fn_parts);
-
- let lcfg = LabelledCFG {
- ast_map: &ty_cx.map,
- cfg: &cfg,
- name: format!("node_{}", code.id()),
- };
- let lcfg = borrowck_dot::DataflowLabeller {
- inner: lcfg,
- variants: variants,
- borrowck_ctxt: &bccx,
- analysis_data: &analysis_data,
- };
- let r = dot::render(&lcfg, &mut out);
- return expand_err_details(r);
- }
- }
-
- fn expand_err_details(r: io::IoResult<()>) -> io::IoResult<()> {
- r.map_err(|ioerr| {
- let orig_detail = ioerr.detail.clone();
- let m = "graphviz::render failed";
- io::IoError {
- detail: Some(match orig_detail {
- None => m.into_string(),
- Some(d) => format!("{}: {}", m, d)
- }),
- ..ioerr
- }
- })
- }
-}
-
pub fn collect_crate_types(session: &Session,
attrs: &[ast::Attribute]) -> Vec<config::CrateType> {
// Unconditionally collect crate types from attributes to make them used
pub mod driver;
pub mod session;
pub mod config;
+pub mod pretty;
pub fn main_args(args: &[String]) -> int {
let ofile = matches.opt_str("o").map(|o| Path::new(o));
let pretty = matches.opt_default("pretty", "normal").map(|a| {
- parse_pretty(&sess, a.as_slice())
+ pretty::parse_pretty(&sess, a.as_slice())
});
match pretty {
Some((ppm, opt_uii)) => {
- driver::pretty_print_input(sess, cfg, &input, ppm, opt_uii, ofile);
+ pretty::pretty_print_input(sess, cfg, &input, ppm, opt_uii, ofile);
return;
}
None => {/* continue */ }
lints
}
+ fn sort_lint_groups(lints: Vec<(&'static str, Vec<lint::LintId>, bool)>)
+ -> Vec<(&'static str, Vec<lint::LintId>)> {
+ let mut lints: Vec<_> = lints.move_iter().map(|(x, y, _)| (x, y)).collect();
+ lints.sort_by(|&(x, _): &(&'static str, Vec<lint::LintId>),
+ &(y, _): &(&'static str, Vec<lint::LintId>)| {
+ x.cmp(&y)
+ });
+ lints
+ }
+
let (plugin, builtin) = lint_store.get_lints().partitioned(|&(_, p)| p);
let plugin = sort_lints(plugin);
let builtin = sort_lints(builtin);
- // FIXME (#7043): We should use the width in character cells rather than
- // the number of codepoints.
+ let (plugin_groups, builtin_groups) = lint_store.get_lint_groups().partitioned(|&(_, _, p)| p);
+ let plugin_groups = sort_lint_groups(plugin_groups);
+ let builtin_groups = sort_lint_groups(builtin_groups);
+
let max_name_len = plugin.iter().chain(builtin.iter())
- .map(|&s| s.name.char_len())
+ .map(|&s| s.name.width(true))
.max().unwrap_or(0);
let padded = |x: &str| {
" ".repeat(max_name_len - x.char_len()).append(x)
print_lints(builtin);
- match (loaded_plugins, plugin.len()) {
- (false, 0) => {
- println!("Compiler plugins can provide additional lints. To see a listing of these, \
- re-run `rustc -W help` with a crate filename.");
+
+
+ let max_name_len = plugin_groups.iter().chain(builtin_groups.iter())
+ .map(|&(s, _)| s.width(true))
+ .max().unwrap_or(0);
+ let padded = |x: &str| {
+ " ".repeat(max_name_len - x.char_len()).append(x)
+ };
+
+ println!("Lint groups provided by rustc:\n");
+ println!(" {} {}", padded("name"), "sub-lints");
+ println!(" {} {}", padded("----"), "---------");
+
+ let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| {
+ for (name, to) in lints.move_iter() {
+ let name = name.chars().map(|x| x.to_lowercase())
+ .collect::<String>().replace("_", "-");
+ let desc = to.move_iter().map(|x| x.as_str()).collect::<Vec<String>>().connect(", ");
+ println!(" {} {}",
+ padded(name.as_slice()), desc);
}
- (false, _) => fail!("didn't load lint plugins but got them anyway!"),
- (true, 0) => println!("This crate does not load any lint plugins."),
- (true, _) => {
- println!("Lint checks provided by plugins loaded by this crate:\n");
- print_lints(plugin);
+ println!("\n");
+ };
+
+ print_lint_groups(builtin_groups);
+
+ match (loaded_plugins, plugin.len(), plugin_groups.len()) {
+ (false, 0, _) | (false, _, 0) => {
+ println!("Compiler plugins can provide additional lints and lint groups. To see a \
+ listing of these, re-run `rustc -W help` with a crate filename.");
+ }
+ (false, _, _) => fail!("didn't load lint plugins but got them anyway!"),
+ (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
+ (true, l, g) => {
+ if l > 0 {
+ println!("Lint checks provided by plugins loaded by this crate:\n");
+ print_lints(plugin);
+ }
+ if g > 0 {
+ println!("Lint groups provided by plugins loaded by this crate:\n");
+ print_lint_groups(plugin_groups);
+ }
}
}
}
}
}
-#[deriving(PartialEq, Show)]
-pub enum PpSourceMode {
- PpmNormal,
- PpmExpanded,
- PpmTyped,
- PpmIdentified,
- PpmExpandedIdentified,
-}
-
-#[deriving(PartialEq, Show)]
-pub enum PpMode {
- PpmSource(PpSourceMode),
- PpmFlowGraph,
-}
-
-fn parse_pretty(sess: &Session, name: &str) -> (PpMode, Option<driver::UserIdentifiedItem>) {
- let mut split = name.splitn(1, '=');
- let first = split.next().unwrap();
- let opt_second = split.next();
- let first = match first {
- "normal" => PpmSource(PpmNormal),
- "expanded" => PpmSource(PpmExpanded),
- "typed" => PpmSource(PpmTyped),
- "expanded,identified" => PpmSource(PpmExpandedIdentified),
- "identified" => PpmSource(PpmIdentified),
- "flowgraph" => PpmFlowGraph,
- _ => {
- sess.fatal(format!(
- "argument to `pretty` must be one of `normal`, \
- `expanded`, `flowgraph=<nodeid>`, `typed`, `identified`, \
- or `expanded,identified`; got {}", name).as_slice());
- }
- };
- let opt_second = opt_second.and_then::<driver::UserIdentifiedItem>(from_str);
- (first, opt_second)
-}
-
fn parse_crate_attrs(sess: &Session, input: &Input) ->
Vec<ast::Attribute> {
let result = match *input {
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! The various pretty print routines.
+
+use back::link;
+
+use driver::config;
+use driver::driver::{mod, CrateAnalysis};
+use driver::session::Session;
+
+use middle::ty;
+use middle::borrowck::{mod, FnPartsWithCFG};
+use middle::borrowck::graphviz as borrowck_dot;
+use middle::cfg;
+use middle::cfg::graphviz::LabelledCFG;
+
+use util::ppaux;
+
+use syntax::ast;
+use syntax::ast_map::{mod, blocks, NodePrinter};
+use syntax::print::{pp, pprust};
+
+use graphviz as dot;
+
+use std::io::{mod, MemReader};
+use std::from_str::FromStr;
+use std::option;
+
+
+#[deriving(PartialEq, Show)]
+pub enum PpSourceMode {
+ PpmNormal,
+ PpmExpanded,
+ PpmTyped,
+ PpmIdentified,
+ PpmExpandedIdentified,
+ PpmExpandedHygiene,
+}
+
+#[deriving(PartialEq, Show)]
+pub enum PpMode {
+ PpmSource(PpSourceMode),
+ PpmFlowGraph,
+}
+
+pub fn parse_pretty(sess: &Session, name: &str) -> (PpMode, Option<UserIdentifiedItem>) {
+ let mut split = name.splitn(1, '=');
+ let first = split.next().unwrap();
+ let opt_second = split.next();
+ let first = match first {
+ "normal" => PpmSource(PpmNormal),
+ "expanded" => PpmSource(PpmExpanded),
+ "typed" => PpmSource(PpmTyped),
+ "expanded,identified" => PpmSource(PpmExpandedIdentified),
+ "expanded,hygiene" => PpmSource(PpmExpandedHygiene),
+ "identified" => PpmSource(PpmIdentified),
+ "flowgraph" => PpmFlowGraph,
+ _ => {
+ sess.fatal(format!(
+ "argument to `pretty` must be one of `normal`, \
+ `expanded`, `flowgraph=<nodeid>`, `typed`, `identified`, \
+ or `expanded,identified`; got {}", name).as_slice());
+ }
+ };
+ let opt_second = opt_second.and_then::<UserIdentifiedItem>(from_str);
+ (first, opt_second)
+}
+
+
+
+// This slightly awkward construction is to allow for each PpMode to
+// choose whether it needs to do analyses (which can consume the
+// Session) and then pass through the session (now attached to the
+// analysis results) on to the chosen pretty-printer, along with the
+// `&PpAnn` object.
+//
+// Note that since the `&PrinterSupport` is freshly constructed on each
+// call, it would not make sense to try to attach the lifetime of `self`
+// to the lifetime of the `&PrinterObject`.
+//
+// (The `use_once_payload` is working around the current lack of once
+// functions in the compiler.)
+
+impl PpSourceMode {
+ /// Constructs a `PrinterSupport` object and passes it to `f`.
+ fn call_with_pp_support<A,B>(&self,
+ sess: Session,
+ krate: &ast::Crate,
+ ast_map: Option<ast_map::Map>,
+ id: String,
+ payload: B,
+ f: |&PrinterSupport, B| -> A) -> A {
+ match *self {
+ PpmNormal | PpmExpanded => {
+ let annotation = NoAnn { sess: sess, ast_map: ast_map };
+ f(&annotation, payload)
+ }
+
+ PpmIdentified | PpmExpandedIdentified => {
+ let annotation = IdentifiedAnnotation { sess: sess, ast_map: ast_map };
+ f(&annotation, payload)
+ }
+ PpmExpandedHygiene => {
+ let annotation = HygieneAnnotation { sess: sess, ast_map: ast_map };
+ f(&annotation, payload)
+ }
+ PpmTyped => {
+ let ast_map = ast_map.expect("--pretty=typed missing ast_map");
+ let analysis = driver::phase_3_run_analysis_passes(sess, krate, ast_map, id);
+ let annotation = TypedAnnotation { analysis: analysis };
+ f(&annotation, payload)
+ }
+ }
+ }
+}
+
+trait SessionCarrier {
+ /// Provides a uniform interface for re-extracting a reference to a
+ /// `Session` from a value that now owns it.
+ fn sess<'a>(&'a self) -> &'a Session;
+}
+
+trait AstMapCarrier {
+ /// Provides a uniform interface for re-extracting a reference to an
+ /// `ast_map::Map` from a value that now owns it.
+ fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map>;
+}
+
+trait PrinterSupport : SessionCarrier + AstMapCarrier {
+ /// Produces the pretty-print annotation object.
+ ///
+ /// Usually implemented via `self as &pprust::PpAnn`.
+ ///
+ /// (Rust does not yet support upcasting from a trait object to
+ /// an object for one of its super-traits.)
+ fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn;
+}
+
+struct NoAnn {
+ sess: Session,
+ ast_map: Option<ast_map::Map>,
+}
+
+impl PrinterSupport for NoAnn {
+ fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self as &pprust::PpAnn }
+}
+
+impl SessionCarrier for NoAnn {
+ fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+}
+
+impl AstMapCarrier for NoAnn {
+ fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map> {
+ self.ast_map.as_ref()
+ }
+}
+
+impl pprust::PpAnn for NoAnn {}
+
+struct IdentifiedAnnotation {
+ sess: Session,
+ ast_map: Option<ast_map::Map>,
+}
+
+impl PrinterSupport for IdentifiedAnnotation {
+ fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self as &pprust::PpAnn }
+}
+
+impl SessionCarrier for IdentifiedAnnotation {
+ fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+}
+
+impl AstMapCarrier for IdentifiedAnnotation {
+ fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map> {
+ self.ast_map.as_ref()
+ }
+}
+
+impl pprust::PpAnn for IdentifiedAnnotation {
+ fn pre(&self,
+ s: &mut pprust::State,
+ node: pprust::AnnNode) -> io::IoResult<()> {
+ match node {
+ pprust::NodeExpr(_) => s.popen(),
+ _ => Ok(())
+ }
+ }
+ fn post(&self,
+ s: &mut pprust::State,
+ node: pprust::AnnNode) -> io::IoResult<()> {
+ match node {
+ pprust::NodeIdent(_) | pprust::NodeName(_) => Ok(()),
+
+ pprust::NodeItem(item) => {
+ try!(pp::space(&mut s.s));
+ s.synth_comment(item.id.to_string())
+ }
+ pprust::NodeBlock(blk) => {
+ try!(pp::space(&mut s.s));
+ s.synth_comment(format!("block {}", blk.id))
+ }
+ pprust::NodeExpr(expr) => {
+ try!(pp::space(&mut s.s));
+ try!(s.synth_comment(expr.id.to_string()));
+ s.pclose()
+ }
+ pprust::NodePat(pat) => {
+ try!(pp::space(&mut s.s));
+ s.synth_comment(format!("pat {}", pat.id))
+ }
+ }
+ }
+}
+
+struct HygieneAnnotation {
+ sess: Session,
+ ast_map: Option<ast_map::Map>,
+}
+
+impl PrinterSupport for HygieneAnnotation {
+ fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self as &pprust::PpAnn }
+}
+
+impl SessionCarrier for HygieneAnnotation {
+ fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+}
+
+impl AstMapCarrier for HygieneAnnotation {
+ fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map> {
+ self.ast_map.as_ref()
+ }
+}
+
+impl pprust::PpAnn for HygieneAnnotation {
+ fn post(&self,
+ s: &mut pprust::State,
+ node: pprust::AnnNode) -> io::IoResult<()> {
+ match node {
+ pprust::NodeIdent(&ast::Ident { name: ast::Name(nm), ctxt }) => {
+ try!(pp::space(&mut s.s));
+ // FIXME #16420: this doesn't display the connections
+ // between syntax contexts
+ s.synth_comment(format!("{}#{}", nm, ctxt))
+ }
+ pprust::NodeName(&ast::Name(nm)) => {
+ try!(pp::space(&mut s.s));
+ s.synth_comment(nm.to_string())
+ }
+ _ => Ok(())
+ }
+ }
+}
+
+
+struct TypedAnnotation {
+ analysis: CrateAnalysis,
+}
+
+impl PrinterSupport for TypedAnnotation {
+ fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self as &pprust::PpAnn }
+}
+
+impl SessionCarrier for TypedAnnotation {
+ fn sess<'a>(&'a self) -> &'a Session { &self.analysis.ty_cx.sess }
+}
+
+impl AstMapCarrier for TypedAnnotation {
+ fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map> {
+ Some(&self.analysis.ty_cx.map)
+ }
+}
+
+impl pprust::PpAnn for TypedAnnotation {
+ fn pre(&self,
+ s: &mut pprust::State,
+ node: pprust::AnnNode) -> io::IoResult<()> {
+ match node {
+ pprust::NodeExpr(_) => s.popen(),
+ _ => Ok(())
+ }
+ }
+ fn post(&self,
+ s: &mut pprust::State,
+ node: pprust::AnnNode) -> io::IoResult<()> {
+ let tcx = &self.analysis.ty_cx;
+ match node {
+ pprust::NodeExpr(expr) => {
+ try!(pp::space(&mut s.s));
+ try!(pp::word(&mut s.s, "as"));
+ try!(pp::space(&mut s.s));
+ try!(pp::word(&mut s.s,
+ ppaux::ty_to_string(
+ tcx,
+ ty::expr_ty(tcx, expr)).as_slice()));
+ s.pclose()
+ }
+ _ => Ok(())
+ }
+ }
+}
+
+fn gather_flowgraph_variants(sess: &Session) -> Vec<borrowck_dot::Variant> {
+ let print_loans = config::FLOWGRAPH_PRINT_LOANS;
+ let print_moves = config::FLOWGRAPH_PRINT_MOVES;
+ let print_assigns = config::FLOWGRAPH_PRINT_ASSIGNS;
+ let print_all = config::FLOWGRAPH_PRINT_ALL;
+ let opt = |print_which| sess.debugging_opt(print_which);
+ let mut variants = Vec::new();
+ if opt(print_all) || opt(print_loans) {
+ variants.push(borrowck_dot::Loans);
+ }
+ if opt(print_all) || opt(print_moves) {
+ variants.push(borrowck_dot::Moves);
+ }
+ if opt(print_all) || opt(print_assigns) {
+ variants.push(borrowck_dot::Assigns);
+ }
+ variants
+}
+
+#[deriving(Clone, Show)]
+pub enum UserIdentifiedItem {
+ ItemViaNode(ast::NodeId),
+ ItemViaPath(Vec<String>),
+}
+
+impl FromStr for UserIdentifiedItem {
+ fn from_str(s: &str) -> Option<UserIdentifiedItem> {
+ let extract_path_parts = || {
+ let v : Vec<_> = s.split_str("::")
+ .map(|x|x.to_string())
+ .collect();
+ Some(ItemViaPath(v))
+ };
+
+ from_str(s).map(ItemViaNode).or_else(extract_path_parts)
+ }
+}
+
+enum NodesMatchingUII<'a> {
+ NodesMatchingDirect(option::Item<ast::NodeId>),
+ NodesMatchingSuffix(ast_map::NodesMatchingSuffix<'a, String>),
+}
+
+impl<'a> Iterator<ast::NodeId> for NodesMatchingUII<'a> {
+ fn next(&mut self) -> Option<ast::NodeId> {
+ match self {
+ &NodesMatchingDirect(ref mut iter) => iter.next(),
+ &NodesMatchingSuffix(ref mut iter) => iter.next(),
+ }
+ }
+}
+
+impl UserIdentifiedItem {
+ fn reconstructed_input(&self) -> String {
+ match *self {
+ ItemViaNode(node_id) => node_id.to_string(),
+ ItemViaPath(ref parts) => parts.connect("::"),
+ }
+ }
+
+ fn all_matching_node_ids<'a>(&'a self, map: &'a ast_map::Map) -> NodesMatchingUII<'a> {
+ match *self {
+ ItemViaNode(node_id) =>
+ NodesMatchingDirect(Some(node_id).move_iter()),
+ ItemViaPath(ref parts) =>
+ NodesMatchingSuffix(map.nodes_matching_suffix(parts.as_slice())),
+ }
+ }
+
+ fn to_one_node_id(self, user_option: &str, sess: &Session, map: &ast_map::Map) -> ast::NodeId {
+ let fail_because = |is_wrong_because| -> ast::NodeId {
+ let message =
+ format!("{:s} needs NodeId (int) or unique \
+ path suffix (b::c::d); got {:s}, which {:s}",
+ user_option,
+ self.reconstructed_input(),
+ is_wrong_because);
+ sess.fatal(message.as_slice())
+ };
+
+ let mut saw_node = ast::DUMMY_NODE_ID;
+ let mut seen = 0u;
+ for node in self.all_matching_node_ids(map) {
+ saw_node = node;
+ seen += 1;
+ if seen > 1 {
+ fail_because("does not resolve uniquely");
+ }
+ }
+ if seen == 0 {
+ fail_because("does not resolve to any item");
+ }
+
+ assert!(seen == 1);
+ return saw_node;
+ }
+}
+
+fn needs_ast_map(ppm: &PpMode, opt_uii: &Option<UserIdentifiedItem>) -> bool {
+ match *ppm {
+ PpmSource(PpmNormal) |
+ PpmSource(PpmIdentified) => opt_uii.is_some(),
+
+ PpmSource(PpmExpanded) |
+ PpmSource(PpmExpandedIdentified) |
+ PpmSource(PpmExpandedHygiene) |
+ PpmSource(PpmTyped) |
+ PpmFlowGraph => true
+ }
+}
+
+fn needs_expansion(ppm: &PpMode) -> bool {
+ match *ppm {
+ PpmSource(PpmNormal) |
+ PpmSource(PpmIdentified) => false,
+
+ PpmSource(PpmExpanded) |
+ PpmSource(PpmExpandedIdentified) |
+ PpmSource(PpmExpandedHygiene) |
+ PpmSource(PpmTyped) |
+ PpmFlowGraph => true
+ }
+}
+
+pub fn pretty_print_input(sess: Session,
+ cfg: ast::CrateConfig,
+ input: &driver::Input,
+ ppm: PpMode,
+ opt_uii: Option<UserIdentifiedItem>,
+ ofile: Option<Path>) {
+ let krate = driver::phase_1_parse_input(&sess, cfg, input);
+ let id = link::find_crate_name(Some(&sess), krate.attrs.as_slice(), input);
+
+ let is_expanded = needs_expansion(&ppm);
+ let (krate, ast_map) = if needs_ast_map(&ppm, &opt_uii) {
+ let k = driver::phase_2_configure_and_expand(&sess, krate, id.as_slice(), None);
+ let (krate, ast_map) = match k {
+ None => return,
+ Some(p) => p,
+ };
+ (krate, Some(ast_map))
+ } else {
+ (krate, None)
+ };
+
+ let src_name = driver::source_name(input);
+ let src = Vec::from_slice(sess.codemap()
+ .get_filemap(src_name.as_slice())
+ .src
+ .as_bytes());
+ let mut rdr = MemReader::new(src);
+
+ let out = match ofile {
+ None => box io::stdout() as Box<Writer+'static>,
+ Some(p) => {
+ let r = io::File::create(&p);
+ match r {
+ Ok(w) => box w as Box<Writer+'static>,
+ Err(e) => fail!("print-print failed to open {} due to {}",
+ p.display(), e),
+ }
+ }
+ };
+
+ match (ppm, opt_uii) {
+ (PpmSource(s), None) =>
+ s.call_with_pp_support(
+ sess, &krate, ast_map, id, out, |annotation, out| {
+ debug!("pretty printing source code {}", s);
+ let sess = annotation.sess();
+ pprust::print_crate(sess.codemap(),
+ sess.diagnostic(),
+ &krate,
+ src_name.to_string(),
+ &mut rdr,
+ out,
+ annotation.pp_ann(),
+ is_expanded)
+ }),
+
+ (PpmSource(s), Some(uii)) =>
+ s.call_with_pp_support(
+ sess, &krate, ast_map, id, (out,uii), |annotation, (out,uii)| {
+ debug!("pretty printing source code {}", s);
+ let sess = annotation.sess();
+ let ast_map = annotation.ast_map()
+ .expect("--pretty missing ast_map");
+ let mut pp_state =
+ pprust::State::new_from_input(sess.codemap(),
+ sess.diagnostic(),
+ src_name.to_string(),
+ &mut rdr,
+ out,
+ annotation.pp_ann(),
+ is_expanded);
+ for node_id in uii.all_matching_node_ids(ast_map) {
+ let node = ast_map.get(node_id);
+ try!(pp_state.print_node(&node));
+ try!(pp::space(&mut pp_state.s));
+ try!(pp_state.synth_comment(ast_map.path_to_string(node_id)));
+ try!(pp::hardbreak(&mut pp_state.s));
+ }
+ pp::eof(&mut pp_state.s)
+ }),
+
+ (PpmFlowGraph, opt_uii) => {
+ debug!("pretty printing flow graph for {}", opt_uii);
+ let uii = opt_uii.unwrap_or_else(|| {
+ sess.fatal(format!("`pretty flowgraph=..` needs NodeId (int) or
+ unique path suffix (b::c::d)").as_slice())
+
+ });
+ let ast_map = ast_map.expect("--pretty flowgraph missing ast_map");
+ let nodeid = uii.to_one_node_id("--pretty", &sess, &ast_map);
+
+ let node = ast_map.find(nodeid).unwrap_or_else(|| {
+ sess.fatal(format!("--pretty flowgraph couldn't find id: {}",
+ nodeid).as_slice())
+ });
+
+ let code = blocks::Code::from_node(node);
+ match code {
+ Some(code) => {
+ let variants = gather_flowgraph_variants(&sess);
+ let analysis = driver::phase_3_run_analysis_passes(sess, &krate,
+ ast_map, id);
+ print_flowgraph(variants, analysis, code, out)
+ }
+ None => {
+ let message = format!("--pretty=flowgraph needs \
+ block, fn, or method; got {:?}",
+ node);
+
+ // point to what was found, if there's an
+ // accessible span.
+ match ast_map.opt_span(nodeid) {
+ Some(sp) => sess.span_fatal(sp, message.as_slice()),
+ None => sess.fatal(message.as_slice())
+ }
+ }
+ }
+ }
+ }.unwrap()
+}
+
+fn print_flowgraph<W:io::Writer>(variants: Vec<borrowck_dot::Variant>,
+ analysis: CrateAnalysis,
+ code: blocks::Code,
+ mut out: W) -> io::IoResult<()> {
+ let ty_cx = &analysis.ty_cx;
+ let cfg = match code {
+ blocks::BlockCode(block) => cfg::CFG::new(ty_cx, &*block),
+ blocks::FnLikeCode(fn_like) => cfg::CFG::new(ty_cx, &*fn_like.body()),
+ };
+ debug!("cfg: {:?}", cfg);
+
+ match code {
+ _ if variants.len() == 0 => {
+ let lcfg = LabelledCFG {
+ ast_map: &ty_cx.map,
+ cfg: &cfg,
+ name: format!("node_{}", code.id()),
+ };
+ let r = dot::render(&lcfg, &mut out);
+ return expand_err_details(r);
+ }
+ blocks::BlockCode(_) => {
+ ty_cx.sess.err("--pretty flowgraph with -Z flowgraph-print \
+ annotations requires fn-like node id.");
+ return Ok(())
+ }
+ blocks::FnLikeCode(fn_like) => {
+ let fn_parts = FnPartsWithCFG::from_fn_like(&fn_like, &cfg);
+ let (bccx, analysis_data) =
+ borrowck::build_borrowck_dataflow_data_for_fn(ty_cx, fn_parts);
+
+ let lcfg = LabelledCFG {
+ ast_map: &ty_cx.map,
+ cfg: &cfg,
+ name: format!("node_{}", code.id()),
+ };
+ let lcfg = borrowck_dot::DataflowLabeller {
+ inner: lcfg,
+ variants: variants,
+ borrowck_ctxt: &bccx,
+ analysis_data: &analysis_data,
+ };
+ let r = dot::render(&lcfg, &mut out);
+ return expand_err_details(r);
+ }
+ }
+
+ fn expand_err_details(r: io::IoResult<()>) -> io::IoResult<()> {
+ r.map_err(|ioerr| {
+ let orig_detail = ioerr.detail.clone();
+ let m = "graphviz::render failed";
+ io::IoError {
+ detail: Some(match orig_detail {
+ None => m.into_string(),
+ Some(d) => format!("{}: {}", m, d)
+ }),
+ ..ioerr
+ }
+ })
+ }
+}
#![allow(deprecated)]
#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
#![feature(default_type_params, phase, unsafe_destructor)]
-#![feature(issue_5723_bootstrap)]
#![allow(unknown_features)] // NOTE: Remove after next snapshot
#![feature(rustc_diagnostic_macros)]
pub mod common;
pub mod ppaux;
pub mod nodemap;
+ pub mod snapshot_vec;
}
pub mod lib {
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
match e.node {
- ast::ExprWhile(cond, _) => {
+ ast::ExprWhile(cond, _, _) => {
match cond.node {
ast::ExprLit(lit) => {
match lit.node {
}
}
-declare_lint!(NON_CAMEL_CASE_TYPES, Warn,
- "types, variants and traits should have camel case names")
+declare_lint!(pub NON_CAMEL_CASE_TYPES, Warn,
+ "types, variants, traits and type parameters should have camel case names")
pub struct NonCamelCaseTypes;
-impl LintPass for NonCamelCaseTypes {
- fn get_lints(&self) -> LintArray {
- lint_array!(NON_CAMEL_CASE_TYPES)
- }
-
- fn check_item(&mut self, cx: &Context, it: &ast::Item) {
+impl NonCamelCaseTypes {
+ fn check_case(&self, cx: &Context, sort: &str, ident: ast::Ident, span: Span) {
fn is_camel_case(ident: ast::Ident) -> bool {
let ident = token::get_ident(ident);
- assert!(!ident.get().is_empty());
+ if ident.get().is_empty() { return true; }
let ident = ident.get().trim_chars('_');
// start with a non-lowercase letter rather than non-uppercase
)).collect()
}
- fn check_case(cx: &Context, sort: &str, ident: ast::Ident, span: Span) {
- let s = token::get_ident(ident);
+ let s = token::get_ident(ident);
- if !is_camel_case(ident) {
- let c = to_camel_case(s.get());
- let m = if c.is_empty() {
- format!("{} `{}` should have a camel case name such as `CamelCase`", sort, s)
- } else {
- format!("{} `{}` should have a camel case name such as `{}`", sort, s, c)
- };
- cx.span_lint(NON_CAMEL_CASE_TYPES, span, m.as_slice());
- }
+ if !is_camel_case(ident) {
+ let c = to_camel_case(s.get());
+ let m = if c.is_empty() {
+ format!("{} `{}` should have a camel case name such as `CamelCase`", sort, s)
+ } else {
+ format!("{} `{}` should have a camel case name such as `{}`", sort, s, c)
+ };
+ cx.span_lint(NON_CAMEL_CASE_TYPES, span, m.as_slice());
}
+ }
+}
+
+impl LintPass for NonCamelCaseTypes {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(NON_CAMEL_CASE_TYPES)
+ }
+ fn check_item(&mut self, cx: &Context, it: &ast::Item) {
let has_extern_repr = it.attrs.iter().map(|attr| {
attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter()
.any(|r| r == &attr::ReprExtern)
match it.node {
ast::ItemTy(..) | ast::ItemStruct(..) => {
- check_case(cx, "type", it.ident, it.span)
+ self.check_case(cx, "type", it.ident, it.span)
}
ast::ItemTrait(..) => {
- check_case(cx, "trait", it.ident, it.span)
+ self.check_case(cx, "trait", it.ident, it.span)
}
ast::ItemEnum(ref enum_definition, _) => {
if has_extern_repr { return }
- check_case(cx, "type", it.ident, it.span);
+ self.check_case(cx, "type", it.ident, it.span);
for variant in enum_definition.variants.iter() {
- check_case(cx, "variant", variant.node.name, variant.span);
+ self.check_case(cx, "variant", variant.node.name, variant.span);
}
}
_ => ()
}
}
+
+ fn check_generics(&mut self, cx: &Context, it: &ast::Generics) {
+ for gen in it.ty_params.iter() {
+ self.check_case(cx, "type parameter", gen.ident, gen.span);
+ }
+ }
}
#[deriving(PartialEq)]
}
}
-declare_lint!(NON_SNAKE_CASE_FUNCTIONS, Warn,
- "methods and functions should have snake case names")
+declare_lint!(pub NON_SNAKE_CASE, Warn,
+ "methods, functions, lifetime parameters and modules should have snake case names")
-pub struct NonSnakeCaseFunctions;
+pub struct NonSnakeCase;
-impl NonSnakeCaseFunctions {
+impl NonSnakeCase {
fn check_snake_case(&self, cx: &Context, sort: &str, ident: ast::Ident, span: Span) {
fn is_snake_case(ident: ast::Ident) -> bool {
let ident = token::get_ident(ident);
- assert!(!ident.get().is_empty());
- let ident = ident.get().trim_chars('_');
+ if ident.get().is_empty() { return true; }
+ let ident = ident.get().trim_left_chars('\'');
+ let ident = ident.trim_chars('_');
let mut allow_underscore = true;
ident.chars().all(|c| {
let mut buf = String::new();
if s.is_empty() { continue; }
for ch in s.chars() {
- if !buf.is_empty() && ch.is_uppercase() {
+ if !buf.is_empty() && buf.as_slice() != "'" && ch.is_uppercase() {
words.push(buf);
buf = String::new();
}
let s = token::get_ident(ident);
if !is_snake_case(ident) {
- cx.span_lint(NON_SNAKE_CASE_FUNCTIONS, span,
+ cx.span_lint(NON_SNAKE_CASE, span,
format!("{} `{}` should have a snake case name such as `{}`",
sort, s, to_snake_case(s.get())).as_slice());
}
}
}
-impl LintPass for NonSnakeCaseFunctions {
+impl LintPass for NonSnakeCase {
fn get_lints(&self) -> LintArray {
- lint_array!(NON_SNAKE_CASE_FUNCTIONS)
+ lint_array!(NON_SNAKE_CASE)
}
fn check_fn(&mut self, cx: &Context,
}
}
+ fn check_item(&mut self, cx: &Context, it: &ast::Item) {
+ match it.node {
+ ast::ItemMod(_) => {
+ self.check_snake_case(cx, "module", it.ident, it.span);
+ }
+ _ => {}
+ }
+ }
+
fn check_ty_method(&mut self, cx: &Context, t: &ast::TypeMethod) {
self.check_snake_case(cx, "trait method", t.ident, t.span);
}
+
+ fn check_lifetime_decl(&mut self, cx: &Context, t: &ast::LifetimeDef) {
+ self.check_snake_case(cx, "lifetime", t.lifetime.name.ident(), t.lifetime.span);
+ }
+
+ fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
+ match &p.node {
+ &ast::PatIdent(_, ref path1, _) => {
+ match cx.tcx.def_map.borrow().find(&p.id) {
+ Some(&def::DefLocal(_, _)) | Some(&def::DefBinding(_, _)) |
+ Some(&def::DefArg(_, _)) => {
+ self.check_snake_case(cx, "variable", path1.node, p.span);
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ }
+
+ fn check_struct_def(&mut self, cx: &Context, s: &ast::StructDef,
+ _: ast::Ident, _: &ast::Generics, _: ast::NodeId) {
+ for sf in s.fields.iter() {
+ match sf.node {
+ ast::StructField_ { kind: ast::NamedField(ident, _), .. } => {
+ self.check_snake_case(cx, "structure field", ident, sf.span);
+ }
+ _ => {}
+ }
+ }
+ }
}
-declare_lint!(NON_UPPERCASE_STATICS, Allow,
+declare_lint!(pub NON_UPPERCASE_STATICS, Allow,
"static constants should have uppercase identifiers")
pub struct NonUppercaseStatics;
_ => {}
}
}
-}
-
-declare_lint!(NON_UPPERCASE_PATTERN_STATICS, Warn,
- "static constants in match patterns should be all caps")
-
-pub struct NonUppercasePatternStatics;
-
-impl LintPass for NonUppercasePatternStatics {
- fn get_lints(&self) -> LintArray {
- lint_array!(NON_UPPERCASE_PATTERN_STATICS)
- }
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
// Lint for constants that look like binding identifiers (#7526)
(&ast::PatIdent(_, ref path1, _), Some(&def::DefStatic(_, false))) => {
let s = token::get_ident(path1.node);
if s.get().chars().any(|c| c.is_lowercase()) {
- cx.span_lint(NON_UPPERCASE_PATTERN_STATICS, path1.span,
+ cx.span_lint(NON_UPPERCASE_STATICS, path1.span,
format!("static constant in pattern `{}` should have an uppercase \
name such as `{}`",
s.get(), s.get().chars().map(|c| c.to_uppercase())
}
}
-declare_lint!(UPPERCASE_VARIABLES, Warn,
- "variable and structure field names should start with a lowercase character")
-
-pub struct UppercaseVariables;
-
-impl LintPass for UppercaseVariables {
- fn get_lints(&self) -> LintArray {
- lint_array!(UPPERCASE_VARIABLES)
- }
-
- fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
- match &p.node {
- &ast::PatIdent(_, ref path1, _) => {
- match cx.tcx.def_map.borrow().find(&p.id) {
- Some(&def::DefLocal(_, _)) | Some(&def::DefBinding(_, _)) |
- Some(&def::DefArg(_, _)) => {
- let s = token::get_ident(path1.node);
- if s.get().len() > 0 && s.get().char_at(0).is_uppercase() {
- cx.span_lint(UPPERCASE_VARIABLES, path1.span,
- "variable names should start with \
- a lowercase character");
- }
- }
- _ => {}
- }
- }
- _ => {}
- }
- }
-
- fn check_struct_def(&mut self, cx: &Context, s: &ast::StructDef,
- _: ast::Ident, _: &ast::Generics, _: ast::NodeId) {
- for sf in s.fields.iter() {
- match sf.node {
- ast::StructField_ { kind: ast::NamedField(ident, _), .. } => {
- let s = token::get_ident(ident);
- if s.get().char_at(0).is_uppercase() {
- cx.span_lint(UPPERCASE_VARIABLES, sf.span,
- "structure field names should start with \
- a lowercase character");
- }
- }
- _ => {}
- }
- }
- }
-}
-
declare_lint!(UNNECESSARY_PARENS, Warn,
"`if`, `match`, `while` and `return` do not need parentheses")
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
let (value, msg, struct_lit_needs_parens) = match e.node {
ast::ExprIf(cond, _, _) => (cond, "`if` condition", true),
- ast::ExprWhile(cond, _) => (cond, "`while` condition", true),
+ ast::ExprWhile(cond, _, _) => (cond, "`while` condition", true),
ast::ExprMatch(head, _) => (head, "`match` head expression", true),
ast::ExprRet(Some(value)) => (value, "`return` value", false),
ast::ExprAssign(_, value) => (value, "assigned value", false),
}
}
-declare_lint!(UNUSED_MUT, Warn,
+declare_lint!(pub UNUSED_MUT, Warn,
"detect mut variables which don't need to be mutable")
pub struct UnusedMut;
/// Current levels of each lint, and where they were set.
levels: HashMap<LintId, LevelSource>,
+
+ /// Map of registered lint groups to what lints they expand to. The bool
+ /// is true if the lint group was added by a plugin.
+ lint_groups: HashMap<&'static str, (Vec<LintId>, bool)>,
}
impl LintStore {
passes: Some(vec!()),
by_name: HashMap::new(),
levels: HashMap::new(),
+ lint_groups: HashMap::new(),
}
}
self.lints.as_slice()
}
+ pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
+ self.lint_groups.iter().map(|(k, &(ref v, b))| (*k, v.clone(), b)).collect()
+ }
+
pub fn register_pass(&mut self, sess: Option<&Session>,
from_plugin: bool, pass: LintPassObject) {
for &lint in pass.get_lints().iter() {
self.passes.get_mut_ref().push(pass);
}
+ pub fn register_group(&mut self, sess: Option<&Session>,
+ from_plugin: bool, name: &'static str,
+ to: Vec<LintId>) {
+ let new = self.lint_groups.insert(name, (to, from_plugin));
+
+ if !new {
+ let msg = format!("duplicate specification of lint group {}", name);
+ match (sess, from_plugin) {
+ // We load builtin lints first, so a duplicate is a compiler bug.
+ // Use early_error when handling -W help with no crate.
+ (None, _) => early_error(msg.as_slice()),
+ (Some(sess), false) => sess.bug(msg.as_slice()),
+
+ // A duplicate name from a plugin is a user error.
+ (Some(sess), true) => sess.err(msg.as_slice()),
+ }
+ }
+ }
+
pub fn register_builtin(&mut self, sess: Option<&Session>) {
macro_rules! add_builtin ( ( $sess:ident, $($name:ident),*, ) => (
{$(
)*}
))
+ macro_rules! add_lint_group ( ( $sess:ident, $name:expr, $($lint:ident),* ) => (
+ self.register_group($sess, false, $name, vec![$(LintId::of(builtin::$lint)),*]);
+ ))
+
add_builtin!(sess,
HardwiredLints,
WhileTrue,
PathStatement,
UnusedResult,
NonCamelCaseTypes,
- NonSnakeCaseFunctions,
+ NonSnakeCase,
NonUppercaseStatics,
- NonUppercasePatternStatics,
- UppercaseVariables,
UnnecessaryParens,
UnusedUnsafe,
UnsafeBlock,
MissingDoc,
)
+ add_lint_group!(sess, "bad_style",
+ NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPERCASE_STATICS)
+
+ add_lint_group!(sess, "unused",
+ UNUSED_IMPORTS, UNUSED_VARIABLE, DEAD_ASSIGNMENT, DEAD_CODE,
+ UNUSED_MUT, UNREACHABLE_CODE)
+
// We have one lint pass defined in this module.
self.register_pass(sess, false, box GatherNodeLevels as LintPassObject);
}
for &(ref lint_name, level) in sess.opts.lint_opts.iter() {
match self.by_name.find_equiv(&lint_name.as_slice()) {
Some(&lint_id) => self.set_level(lint_id, (level, CommandLine)),
- None => sess.err(format!("unknown {} flag: {}",
- level.as_str(), lint_name).as_slice()),
+ None => {
+ match self.lint_groups.iter().map(|(&x, &(ref y, _))| (x, y.clone()))
+ .collect::<HashMap<&'static str, Vec<LintId>>>()
+ .find_equiv(&lint_name.as_slice()) {
+ Some(v) => {
+ v.iter()
+ .map(|lint_id: &LintId|
+ self.set_level(*lint_id, (level, CommandLine)))
+ .collect::<Vec<()>>();
+ }
+ None => sess.err(format!("unknown {} flag: {}",
+ level.as_str(), lint_name).as_slice()),
+ }
+ }
}
}
}
krate: krate,
exported_items: exported_items,
lints: lint_store,
- level_stack: vec!(),
+ level_stack: vec![],
node_levels: RefCell::new(HashMap::new()),
}
}
let mut pushed = 0u;
for result in gather_attrs(attrs).move_iter() {
- let (lint_id, level, span) = match result {
+ let v = match result {
Err(span) => {
self.tcx.sess.span_err(span, "malformed lint attribute");
continue;
}
Ok((lint_name, level, span)) => {
match self.lints.by_name.find_equiv(&lint_name.get()) {
- Some(&lint_id) => (lint_id, level, span),
+ Some(&lint_id) => vec![(lint_id, level, span)],
None => {
- self.span_lint(builtin::UNRECOGNIZED_LINT, span,
- format!("unknown `{}` attribute: `{}`",
- level.as_str(), lint_name).as_slice());
- continue;
+ match self.lints.lint_groups.find_equiv(&lint_name.get()) {
+ Some(&(ref v, _)) => v.iter()
+ .map(|lint_id: &LintId|
+ (*lint_id, level, span))
+ .collect(),
+ None => {
+ self.span_lint(builtin::UNRECOGNIZED_LINT, span,
+ format!("unknown `{}` attribute: `{}`",
+ level.as_str(), lint_name).as_slice());
+ continue;
+ }
+ }
}
}
}
};
- let now = self.lints.get_level_source(lint_id).val0();
- if now == Forbid && level != Forbid {
- let lint_name = lint_id.as_str();
- self.tcx.sess.span_err(span,
- format!("{}({}) overruled by outer forbid({})",
- level.as_str(), lint_name, lint_name).as_slice());
- } else if now != level {
- let src = self.lints.get_level_source(lint_id).val1();
- self.level_stack.push((lint_id, (now, src)));
- pushed += 1;
- self.lints.set_level(lint_id, (level, Node(span)));
+ for (lint_id, level, span) in v.move_iter() {
+ let now = self.lints.get_level_source(lint_id).val0();
+ if now == Forbid && level != Forbid {
+ let lint_name = lint_id.as_str();
+ self.tcx.sess.span_err(span,
+ format!("{}({}) overruled by outer forbid({})",
+ level.as_str(), lint_name,
+ lint_name).as_slice());
+ } else if now != level {
+ let src = self.lints.get_level_source(lint_id).val1();
+ self.level_stack.push((lint_id, (now, src)));
+ pushed += 1;
+ self.lints.set_level(lint_id, (level, Node(span)));
+ }
}
}
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
self.add_node(expr.id, [then_exit, else_exit]) // 4, 5
}
- ast::ExprWhile(ref cond, ref body) => {
+ ast::ExprWhile(ref cond, ref body, _) => {
//
// [pred]
// |
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
fn visit_expr(&mut self, e: &ast::Expr, cx:Context) {
match e.node {
- ast::ExprWhile(ref e, ref b) => {
+ ast::ExprWhile(ref e, ref b, _) => {
self.visit_expr(&**e, cx);
self.visit_block(&**b, Loop);
}
fn initial_value(&self) -> bool;
}
-#[cfg(stage0)]
-struct PropagationContext<'a, 'b, O> {
- dfcx: &'a mut DataFlowContext<'b, O>,
- changed: bool
-}
-
-#[cfg(not(stage0))]
struct PropagationContext<'a, 'b:'a, O:'a> {
dfcx: &'a mut DataFlowContext<'b, O>,
changed: bool
ps: &mut pprust::State,
node: pprust::AnnNode) -> io::IoResult<()> {
let id = match node {
+ pprust::NodeIdent(_) | pprust::NodeName(_) => 0,
pprust::NodeExpr(expr) => expr.id,
pprust::NodeBlock(blk) => blk.id,
pprust::NodeItem(_) => 0,
// supplies types from the tree. After type checking is complete, you
// can just use the tcx as the typer.
-#[cfg(stage0)]
-pub struct ExprUseVisitor<'d,'t,TYPER> {
- typer: &'t TYPER,
- mc: mc::MemCategorizationContext<'t,TYPER>,
- delegate: &'d mut Delegate+'d,
-}
-
-#[cfg(not(stage0))]
pub struct ExprUseVisitor<'d,'t,TYPER:'t> {
typer: &'t TYPER,
mc: mc::MemCategorizationContext<'t,TYPER>,
self.walk_block(&**blk);
}
- ast::ExprWhile(ref cond_expr, ref blk) => {
+ ast::ExprWhile(ref cond_expr, ref blk, _) => {
self.consume_expr(&**cond_expr);
self.walk_block(&**blk);
}
self.propagate_through_expr(&**cond, ln)
}
- ExprWhile(ref cond, ref blk) => {
+ ExprWhile(ref cond, ref blk, _) => {
self.propagate_through_loop(expr,
WhileLoop(cond.clone()),
&**blk,
fn span(&self) -> Span { self.span }
}
-#[cfg(stage0)]
-pub struct MemCategorizationContext<'t,TYPER> {
- typer: &'t TYPER
-}
-
-#[cfg(not(stage0))]
pub struct MemCategorizationContext<'t,TYPER:'t> {
typer: &'t TYPER
}
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
visitor.region_maps.mark_as_terminating_scope(body.id);
}
- ast::ExprWhile(expr, body) => {
+ ast::ExprWhile(expr, body, _) => {
visitor.region_maps.mark_as_terminating_scope(expr.id);
visitor.region_maps.mark_as_terminating_scope(body.id);
}
use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate};
use syntax::ast::{DeclItem, DefId, Expr, ExprAgain, ExprBreak, ExprField};
-use syntax::ast::{ExprFnBlock, ExprForLoop, ExprLoop, ExprMethodCall};
+use syntax::ast::{ExprFnBlock, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall};
use syntax::ast::{ExprPath, ExprProc, ExprStruct, ExprUnboxedFn, FnDecl};
use syntax::ast::{ForeignItem, ForeignItemFn, ForeignItemStatic, Generics};
use syntax::ast::{Ident, ImplItem, Item, ItemEnum, ItemFn, ItemForeignMod};
.contains_key(&name) {
match import_resolution.type_target {
Some(ref target) if !target.shadowable => {
- self.session.span_err(import_span,
- "import conflicts with imported \
- crate in this module");
+ let msg = format!("import `{}` conflicts with imported \
+ crate in this module",
+ token::get_name(name).get());
+ self.session.span_err(import_span, msg.as_slice());
}
Some(_) | None => {}
}
match *name_bindings.value_def.borrow() {
None => {}
Some(ref value) => {
- self.session.span_err(import_span,
- "import conflicts with value \
- in this module");
+ let msg = format!("import `{}` conflicts with value \
+ in this module",
+ token::get_name(name).get());
+ self.session.span_err(import_span, msg.as_slice());
match value.value_span {
None => {}
Some(span) => {
match *name_bindings.type_def.borrow() {
None => {}
Some(ref ty) => {
- self.session.span_err(import_span,
- "import conflicts with type in \
- this module");
+ let msg = format!("import `{}` conflicts with type in \
+ this module",
+ token::get_name(name).get());
+ self.session.span_err(import_span, msg.as_slice());
match ty.type_span {
None => {}
Some(span) => {
visit::walk_expr(self, expr, ());
}
- ExprLoop(_, Some(label)) => {
+ ExprLoop(_, Some(label)) | ExprWhile(_, _, Some(label)) => {
self.with_label_rib(|this| {
let def_like = DlDef(DefLabel(expr.id));
* As we proceed `bound_ptrs` are filled with pointers to values to be bound,
* these pointers are stored in llmatch variables just before executing `data` arm.
*/
-#[cfg(not(stage0))]
struct Match<'a, 'b:'a> {
pats: Vec<Gc<ast::Pat>>,
data: &'a ArmData<'a, 'b>,
bound_ptrs: Vec<(Ident, ValueRef)>
}
-///Dox
-#[cfg(stage0)]
-struct Match<'a, 'b> {
- pats: Vec<Gc<ast::Pat>>,
- data: &'a ArmData<'a, 'b>,
- bound_ptrs: Vec<(Ident, ValueRef)>
-}
-
impl<'a, 'b> Repr for Match<'a, 'b> {
fn repr(&self, tcx: &ty::ctxt) -> String {
if tcx.sess.verbose() {
// except according to those terms.
#![allow(dead_code)] // FFI wrappers
-#![allow(non_snake_case_functions)]
+#![allow(non_snake_case)]
use llvm;
use llvm::{CallConv, AtomicBinOp, AtomicOrdering, AsmDialect, AttrBuilder};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_uppercase_pattern_statics)]
+#![allow(non_uppercase_statics)]
use llvm;
use llvm::{Integer, Pointer, Float, Double, Struct, Array};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_uppercase_pattern_statics)]
+#![allow(non_uppercase_statics)]
use libc::c_uint;
use std::cmp;
// The classification code for the x86_64 ABI is taken from the clay language
// https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp
-#![allow(non_uppercase_pattern_statics)]
+#![allow(non_uppercase_statics)]
use llvm;
use llvm::{Integer, Pointer, Float, Double};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_camel_case_types, non_snake_case_functions)]
+#![allow(non_camel_case_types, non_snake_case)]
//! Code that is useful in various trans modules.
static UNKNOWN_FILE_METADATA: DIFile = (0 as DIFile);
static UNKNOWN_SCOPE_METADATA: DIScope = (0 as DIScope);
+static FLAGS_NONE: c_uint = 0;
+static FLAGS_ARTIFICAL: c_uint = llvm::debuginfo::FlagArtificial as c_uint;
+
//=-----------------------------------------------------------------------------
// Public Interface of debuginfo module
//=-----------------------------------------------------------------------------
!cx.reachable.contains(&node_id)
}
-#[allow(non_snake_case_functions)]
+#[allow(non_snake_case)]
fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray {
return unsafe {
llvm::LLVMDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32)
llvm_type: Type,
type_metadata: DIType,
offset: MemberOffset,
+ flags: c_uint
}
// A factory for MemberDescriptions. It produces a list of member descriptions
llvm_type: type_of::type_of(cx, field.mt.ty),
type_metadata: type_metadata(cx, field.mt.ty, self.span),
offset: offset,
+ flags: FLAGS_NONE,
}
}).collect()
}
llvm_type: type_of::type_of(cx, component_type),
type_metadata: type_metadata(cx, component_type, self.span),
offset: ComputedMemberOffset,
+ flags: FLAGS_NONE,
}
}).collect()
}
llvm_type: variant_llvm_type,
type_metadata: variant_type_metadata,
offset: FixedMemberOffset { bytes: 0 },
+ flags: FLAGS_NONE
}
}).collect()
},
llvm_type: variant_llvm_type,
type_metadata: variant_type_metadata,
offset: FixedMemberOffset { bytes: 0 },
+ flags: FLAGS_NONE
}
]
}
llvm_type: non_null_llvm_type,
type_metadata: non_null_type_metadata,
offset: FixedMemberOffset { bytes: 0 },
+ flags: FLAGS_NONE
};
let unique_type_id = debug_context(cx).type_map
llvm_type: artificial_struct_llvm_type,
type_metadata: artificial_struct_metadata,
offset: FixedMemberOffset { bytes: 0 },
+ flags: FLAGS_NONE
}
]
},
llvm_type: variant_llvm_type,
type_metadata: variant_type_metadata,
offset: FixedMemberOffset { bytes: 0 },
+ flags: FLAGS_NONE
}
]
},
_ => type_metadata(cx, ty, self.span)
},
offset: ComputedMemberOffset,
+ flags: if self.discriminant_type_metadata.is_some() && i == 0 {
+ FLAGS_ARTIFICAL
+ } else {
+ FLAGS_NONE
+ }
}
}).collect()
}
bytes_to_bits(member_size),
bytes_to_bits(member_align),
bytes_to_bits(member_offset),
- 0,
+ member_description.flags,
member_description.type_metadata)
}
})
llvm_type: *member_llvm_types.get(0),
type_metadata: type_metadata(cx, int_type, codemap::DUMMY_SP),
offset: ComputedMemberOffset,
+ flags: FLAGS_ARTIFICAL,
},
MemberDescription {
name: "drop_glue".to_string(),
llvm_type: *member_llvm_types.get(1),
type_metadata: nil_pointer_type_metadata,
offset: ComputedMemberOffset,
+ flags: FLAGS_ARTIFICAL,
},
MemberDescription {
name: "prev".to_string(),
llvm_type: *member_llvm_types.get(2),
type_metadata: nil_pointer_type_metadata,
offset: ComputedMemberOffset,
+ flags: FLAGS_ARTIFICAL,
},
MemberDescription {
name: "next".to_string(),
llvm_type: *member_llvm_types.get(3),
type_metadata: nil_pointer_type_metadata,
offset: ComputedMemberOffset,
+ flags: FLAGS_ARTIFICAL,
},
MemberDescription {
name: "val".to_string(),
llvm_type: *member_llvm_types.get(4),
type_metadata: content_type_metadata,
offset: ComputedMemberOffset,
+ flags: FLAGS_ARTIFICAL,
}
];
llvm_type: *member_llvm_types.get(0),
type_metadata: element_type_metadata,
offset: ComputedMemberOffset,
+ flags: FLAGS_ARTIFICAL
},
MemberDescription {
name: "length".to_string(),
llvm_type: *member_llvm_types.get(1),
type_metadata: type_metadata(cx, ty::mk_uint(), span),
offset: ComputedMemberOffset,
+ flags: FLAGS_ARTIFICAL
},
];
}
#[inline]
-#[allow(non_snake_case_functions)]
+#[allow(non_snake_case)]
fn DIB(cx: &CrateContext) -> DIBuilderRef {
cx.dbg_cx.get_ref().builder
}
}
}
- ast::ExprWhile(ref cond_exp, ref loop_body) => {
+ ast::ExprWhile(ref cond_exp, ref loop_body, _) => {
walk_expr(cx, &**cond_exp, scope_stack, scope_map);
with_new_scope(cx,
ast::ExprRet(ex) => {
controlflow::trans_ret(bcx, ex)
}
- ast::ExprWhile(ref cond, ref body) => {
+ ast::ExprWhile(ref cond, ref body, _) => {
controlflow::trans_while(bcx, expr.id, &**cond, &**body)
}
ast::ExprForLoop(ref pat, ref head, ref body, _) => {
ty::ty_uniq(content_ty) => {
match ty::get(content_ty).sty {
ty::ty_vec(ty, None) => {
- tvec::make_drop_glue_unboxed(bcx, v0, ty)
+ tvec::make_drop_glue_unboxed(bcx, v0, ty, true)
}
ty::ty_str => {
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
- tvec::make_drop_glue_unboxed(bcx, v0, unit_ty)
+ tvec::make_drop_glue_unboxed(bcx, v0, unit_ty, true)
}
ty::ty_trait(..) => {
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
None);
bcx
}
- ty::ty_vec(ty, None) => tvec::make_drop_glue_unboxed(bcx, v0, ty),
+ ty::ty_vec(ty, None) => tvec::make_drop_glue_unboxed(bcx, v0, ty, false),
_ => {
assert!(ty::type_is_sized(bcx.tcx(), t));
if ty::type_needs_drop(bcx.tcx(), t) &&
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_uppercase_pattern_statics)]
+#![allow(non_uppercase_statics)]
use llvm;
use llvm::{SequentiallyConsistent, Acquire, Release, Xchg, ValueRef};
pub fn make_drop_glue_unboxed<'a>(
bcx: &'a Block<'a>,
vptr: ValueRef,
- unit_ty: ty::t)
+ unit_ty: ty::t,
+ should_deallocate: bool)
-> &'a Block<'a> {
let not_null = IsNotNull(bcx, vptr);
with_cond(bcx, not_null, |bcx| {
let tcx = bcx.tcx();
let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
- let len = get_len(bcx, vptr);
let dataptr = get_dataptr(bcx, vptr);
let bcx = if ty::type_needs_drop(tcx, unit_ty) {
+ let len = get_len(bcx, vptr);
iter_vec_raw(bcx, dataptr, unit_ty, len, glue::drop_ty)
} else {
bcx
};
- let not_null = IsNotNull(bcx, dataptr);
- with_cond(bcx, not_null, |bcx| {
- glue::trans_exchange_free(bcx, dataptr, 0, 8)
- })
+ if should_deallocate {
+ let not_null = IsNotNull(bcx, dataptr);
+ with_cond(bcx, not_null, |bcx| {
+ // FIXME: #13994: the old `Box<[T]>` will not support sized deallocation
+ glue::trans_exchange_free(bcx, dataptr, 0, 8)
+ })
+ } else {
+ bcx
+ }
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_uppercase_pattern_statics)]
+#![allow(non_uppercase_statics)]
use llvm;
use llvm::{TypeRef, Bool, False, True, TypeKind, ValueRef};
use middle::subst;
use middle::ty;
use middle::typeck;
-use middle::typeck::MethodCall;
use middle::ty_fold;
use middle::ty_fold::{TypeFoldable,TypeFolder};
use middle;
macro_rules! def_type_content_sets(
(mod $mname:ident { $($name:ident = $bits:expr),+ }) => {
+ #[allow(non_snake_case)]
mod $mname {
use middle::ty::TypeContents;
$(pub static $name: TypeContents = TypeContents { bits: $bits };)+
span_err!(fcx.tcx().sess, call_expression.span, E0056,
"overloaded calls are experimental");
span_note!(fcx.tcx().sess, call_expression.span,
- "add `#[feature(overloaded_calls)]` to \
+ "add `#![feature(overloaded_calls)]` to \
the crate attributes to enable");
}
}
};
+ let expr_type = fcx.expr_ty(&*iterator_expr);
let method = method::lookup_in_trait(fcx,
iterator_expr.span,
Some(&*iterator_expr),
token::intern("next"),
trait_did,
- fcx.expr_ty(&*iterator_expr),
+ expr_type,
[],
DontAutoderefReceiver,
IgnoreStaticMethods);
let method_type = match method {
Some(ref method) => method.ty,
None => {
- fcx.tcx().sess.span_err(iterator_expr.span,
- "`for` loop expression does not \
- implement the `Iterator` trait");
+ let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(expr_type);
+
+ if !ty::type_is_error(true_expr_type) {
+ let ty_string = fcx.infcx().ty_to_string(true_expr_type);
+ fcx.tcx().sess.span_err(iterator_expr.span,
+ format!("`for` loop expression has type `{}` which does \
+ not implement the `Iterator` trait",
+ ty_string).as_slice());
+ }
ty::mk_err()
}
};
check_then_else(fcx, &**cond, &**then_blk, opt_else_expr.clone(),
id, expr.span, expected);
}
- ast::ExprWhile(ref cond, ref body) => {
+ ast::ExprWhile(ref cond, ref body, _) => {
check_expr_has_type(fcx, &**cond, ty::mk_bool());
check_block_no_value(fcx, &**body);
let cond_ty = fcx.expr_ty(&**cond);
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
rcx.set_repeating_scope(repeating_scope);
}
- ast::ExprWhile(ref cond, ref body) => {
+ ast::ExprWhile(ref cond, ref body, _) => {
let repeating_scope = rcx.set_repeating_scope(cond.id);
rcx.visit_expr(&**cond, ());
expr.repr(tcx), callee_scope);
let mc = mc::MemCategorizationContext::new(rcx);
let expr_cmt = ignore_err!(mc.cat_expr(expr));
- let region_min = ty::ReScope(callee_scope);
- link_region(rcx, expr.span, region_min, ty::ImmBorrow, expr_cmt);
+ let borrow_region = ty::ReScope(callee_scope);
+ link_region(rcx, expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
}
fn link_region_from_node_type(rcx: &Rcx,
fn link_region(rcx: &Rcx,
span: Span,
- region_min: ty::Region,
- kind: ty::BorrowKind,
- cmt_borrowed: mc::cmt) {
+ borrow_region: ty::Region,
+ borrow_kind: ty::BorrowKind,
+ borrow_cmt: mc::cmt) {
/*!
- * Informs the inference engine that a borrow of `cmt`
- * must have the borrow kind `kind` and lifetime `region_min`.
- * If `cmt` is a deref of a region pointer with
- * lifetime `r_borrowed`, this will add the constraint that
- * `region_min <= r_borrowed`.
+ * Informs the inference engine that `borrow_cmt` is being
+ * borrowed with kind `borrow_kind` and lifetime `borrow_region`.
+ * In order to ensure borrowck is satisfied, this may create
+ * constraints between regions, as explained in
+ * `link_reborrowed_region()`.
*/
- // Iterate through all the things that must be live at least
- // for the lifetime `region_min` for the borrow to be valid:
- let mut cmt_borrowed = cmt_borrowed;
+ let mut borrow_cmt = borrow_cmt;
+ let mut borrow_kind = borrow_kind;
+
loop {
- debug!("link_region(region_min={}, kind={}, cmt_borrowed={})",
- region_min.repr(rcx.tcx()),
- kind.repr(rcx.tcx()),
- cmt_borrowed.repr(rcx.tcx()));
- match cmt_borrowed.cat.clone() {
- mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) |
- mc::cat_deref(base, _, mc::Implicit(_, r_borrowed)) => {
- // References to an upvar `x` are translated to
- // `*x`, since that is what happens in the
- // underlying machine. We detect such references
- // and treat them slightly differently, both to
- // offer better error messages and because we need
- // to infer the kind of borrow (mut, const, etc)
- // to use for each upvar.
- let cause = match base.cat {
- mc::cat_upvar(ref upvar_id, _) => {
- match rcx.fcx.inh.upvar_borrow_map.borrow_mut()
- .find_mut(upvar_id) {
- Some(upvar_borrow) => {
- debug!("link_region: {} <= {}",
- region_min.repr(rcx.tcx()),
- upvar_borrow.region.repr(rcx.tcx()));
- adjust_upvar_borrow_kind_for_loan(
- *upvar_id,
- upvar_borrow,
- kind);
- infer::ReborrowUpvar(span, *upvar_id)
- }
- None => {
- rcx.tcx().sess.span_bug(
- span,
- format!("Illegal upvar id: {}",
- upvar_id.repr(
- rcx.tcx())).as_slice());
- }
- }
+ debug!("link_region(borrow_region={}, borrow_kind={}, borrow_cmt={})",
+ borrow_region.repr(rcx.tcx()),
+ borrow_kind.repr(rcx.tcx()),
+ borrow_cmt.repr(rcx.tcx()));
+ match borrow_cmt.cat.clone() {
+ mc::cat_deref(ref_cmt, _,
+ mc::Implicit(ref_kind, ref_region)) |
+ mc::cat_deref(ref_cmt, _,
+ mc::BorrowedPtr(ref_kind, ref_region)) => {
+ match link_reborrowed_region(rcx, span,
+ borrow_region, borrow_kind,
+ ref_cmt, ref_region, ref_kind) {
+ Some((c, k)) => {
+ borrow_cmt = c;
+ borrow_kind = k;
}
-
- _ => {
- infer::Reborrow(span)
+ None => {
+ return;
}
- };
-
- debug!("link_region: {} <= {}",
- region_min.repr(rcx.tcx()),
- r_borrowed.repr(rcx.tcx()));
- rcx.fcx.mk_subr(cause, region_min, r_borrowed);
-
- if kind != ty::ImmBorrow {
- // If this is a mutable borrow, then the thing
- // being borrowed will have to be unique.
- // In user code, this means it must be an `&mut`
- // borrow, but for an upvar, we might opt
- // for an immutable-unique borrow.
- adjust_upvar_borrow_kind_for_unique(rcx, base);
}
-
- // Borrowing an `&mut` pointee for `region_min` is
- // only valid if the pointer resides in a unique
- // location which is itself valid for
- // `region_min`. We don't care about the unique
- // part, but we may need to influence the
- // inference to ensure that the location remains
- // valid.
- //
- // FIXME(#8624) fixing borrowck will require this
- // if m == ast::m_mutbl {
- // cmt_borrowed = cmt_base;
- // } else {
- // return;
- // }
- return;
}
+
mc::cat_discr(cmt_base, _) |
mc::cat_downcast(cmt_base) |
mc::cat_deref(cmt_base, _, mc::GcPtr(..)) |
mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
mc::cat_interior(cmt_base, _) => {
- // Interior or owned data requires its base to be valid
- cmt_borrowed = cmt_base;
+ // Borrowing interior or owned data requires the base
+ // to be valid and borrowable in the same fashion.
+ borrow_cmt = cmt_base;
+ borrow_kind = borrow_kind;
}
+
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_static_item |
mc::cat_copied_upvar(..) |
}
}
+fn link_reborrowed_region(rcx: &Rcx,
+ span: Span,
+ borrow_region: ty::Region,
+ borrow_kind: ty::BorrowKind,
+ ref_cmt: mc::cmt,
+ ref_region: ty::Region,
+ ref_kind: ty::BorrowKind)
+ -> Option<(mc::cmt, ty::BorrowKind)>
+{
+ /*!
+ * This is the most complicated case: the path being borrowed is
+ * itself the referent of a borrowed pointer. Let me give an
+ * example fragment of code to make clear(er) the situation:
+ *
+ * let r: &'a mut T = ...; // the original reference "r" has lifetime 'a
+ * ...
+ * &'z *r // the reborrow has lifetime 'z
+ *
+ * Now, in this case, our primary job is to add the inference
+ * constraint that `'z <= 'a`. Given this setup, let's clarify the
+ * parameters in (roughly) terms of the example:
+ *
+ * A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T`
+ * borrow_region ^~ ref_region ^~
+ * borrow_kind ^~ ref_kind ^~
+ * ref_cmt ^
+ *
+ * Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc).
+ *
+ * Unfortunately, there are some complications beyond the simple
+ * scenario I just painted:
+ *
+ * 1. The reference `r` might in fact be a "by-ref" upvar. In that
+ * case, we have two jobs. First, we are inferring whether this reference
+ * should be an `&T`, `&mut T`, or `&uniq T` reference, and we must
+ * adjust that based on this borrow (e.g., if this is an `&mut` borrow,
+ * then `r` must be an `&mut` reference). Second, whenever we link
+ * two regions (here, `'z <= 'a`), we supply a *cause*, and in this
+ * case we adjust the cause to indicate that the reference being
+ * "reborrowed" is itself an upvar. This provides a nicer error message
+ * should something go wrong.
+ *
+ * 2. There may in fact be more levels of reborrowing. In the
+ * example, I said the borrow was like `&'z *r`, but it might
+ * in fact be a borrow like `&'z **q` where `q` has type `&'a
+ * &'b mut T`. In that case, we want to ensure that `'z <= 'a`
+ * and `'z <= 'b`. This is explained more below.
+ *
+ * The return value of this function indicates whether we need to
+ * recurse and process `ref_cmt` (see case 2 above).
+ */
+
+ // Detect references to an upvar `x`:
+ let cause = match ref_cmt.cat {
+ mc::cat_upvar(ref upvar_id, _) => {
+ let mut upvar_borrow_map =
+ rcx.fcx.inh.upvar_borrow_map.borrow_mut();
+ match upvar_borrow_map.find_mut(upvar_id) {
+ Some(upvar_borrow) => {
+ // Adjust mutability that we infer for the upvar
+ // so it can accommodate being borrowed with
+ // mutability `kind`:
+ adjust_upvar_borrow_kind_for_loan(*upvar_id,
+ upvar_borrow,
+ borrow_kind);
+
+ infer::ReborrowUpvar(span, *upvar_id)
+ }
+ None => {
+ rcx.tcx().sess.span_bug(
+ span,
+ format!("Illegal upvar id: {}",
+ upvar_id.repr(
+ rcx.tcx())).as_slice());
+ }
+ }
+ }
+
+ _ => {
+ infer::Reborrow(span)
+ }
+ };
+
+ debug!("link_reborrowed_region: {} <= {}",
+ borrow_region.repr(rcx.tcx()),
+ ref_region.repr(rcx.tcx()));
+ rcx.fcx.mk_subr(cause, borrow_region, ref_region);
+
+ // Decide whether we need to recurse and link any regions within
+ // the `ref_cmt`. This is concerned for the case where the value
+ // being reborrowed is in fact a borrowed pointer found within
+ // another borrowed pointer. For example:
+ //
+ // let p: &'b &'a mut T = ...;
+ // ...
+ // &'z **p
+ //
+ // What makes this case particularly tricky is that, if the data
+ // being borrowed is a `&mut` or `&uniq` borrow, borrowck requires
+ // not only that `'z <= 'a`, (as before) but also `'z <= 'b`
+ // (otherwise the user might mutate through the `&mut T` reference
+ // after `'b` expires and invalidate the borrow we are looking at
+ // now).
+ //
+ // So let's re-examine our parameters in light of this more
+ // complicated (possible) scenario:
+ //
+ // A borrow of: `& 'z bk * * p` where `p` has type `&'b bk & 'a bk T`
+ // borrow_region ^~ ref_region ^~
+ // borrow_kind ^~ ref_kind ^~
+ // ref_cmt ^~~
+ //
+ // (Note that since we have not examined `ref_cmt.cat`, we don't
+ // know whether this scenario has occurred; but I wanted to show
+ // how all the types get adjusted.)
+ match ref_kind {
+ ty::ImmBorrow => {
+ // The reference being reborrowed is a sharable ref of
+ // type `&'a T`. In this case, it doesn't matter where we
+ // *found* the `&T` pointer, the memory it references will
+ // be valid and immutable for `'a`. So we can stop here.
+ //
+ // (Note that the `borrow_kind` must also be ImmBorrow or
+ // else the user is borrowed imm memory as mut memory,
+ // which means they'll get an error downstream in borrowck
+ // anyhow.)
+ return None;
+ }
+
+ ty::MutBorrow | ty::UniqueImmBorrow => {
+ // The reference being reborrowed is either an `&mut T` or
+ // `&uniq T`. This is the case where recursion is needed.
+ //
+ // One interesting twist is that we can weaken the borrow
+ // kind when we recurse: to reborrow an `&mut` referent as
+ // mutable, borrowck requires a unique path to the `&mut`
+ // reference but not necessarily a *mutable* path.
+ let new_borrow_kind = match borrow_kind {
+ ty::ImmBorrow =>
+ ty::ImmBorrow,
+ ty::MutBorrow | ty::UniqueImmBorrow =>
+ ty::UniqueImmBorrow
+ };
+ return Some((ref_cmt, new_borrow_kind));
+ }
+ }
+}
+
fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx,
lhs: &ast::Expr) {
/*!
fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
cmt: mc::cmt) {
+ /*!
+ * Indicates that `cmt` is being directly mutated (e.g., assigned
+ * to). If cmt contains any by-ref upvars, this implies that
+ * those upvars must be borrowed using an `&mut` borow.
+ */
+
let mut cmt = cmt;
loop {
debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
r_borrow,
mt {ty: inner_ty, mutbl: mutbl_b});
- if_ok!(sub.tys(a_borrowed, b));
+ try!(sub.tys(a_borrowed, b));
Ok(Some(AutoDerefRef(AutoDerefRef {
autoderefs: 1,
let r_borrow = self.get_ref().infcx.next_region_var(coercion);
let unsized_ty = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow,
mt {ty: t_a, mutbl: mutbl_b});
- if_ok!(self.get_ref().infcx.try(|| sub.tys(unsized_ty, b)));
+ try!(self.get_ref().infcx.try(|| sub.tys(unsized_ty, b)));
Ok(Some(AutoDerefRef(AutoDerefRef {
autoderefs: 0,
autoref: Some(ty::AutoPtr(r_borrow,
let ty = ty::mk_rptr(self.get_ref().infcx.tcx,
r_borrow,
ty::mt{ty: ty, mutbl: mt_b.mutbl});
- if_ok!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
+ try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
debug!("Success, coerced with AutoDerefRef(1, \
AutoPtr(AutoUnsize({:?})))", kind);
Ok(Some(AutoDerefRef(AutoDerefRef {
match self.unsize_ty(sty_a, t_b) {
Some((ty, kind)) => {
let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty);
- if_ok!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
+ try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
debug!("Success, coerced with AutoDerefRef(1, \
AutoUnsizeUniq({:?}))", kind);
Ok(Some(AutoDerefRef(AutoDerefRef {
}
};
- if_ok!(self.subtype(a_borrowed, b));
+ try!(self.subtype(a_borrowed, b));
Ok(Some(AutoDerefRef(AutoDerefRef {
autoderefs: 1,
autoref: Some(AutoPtr(r_a, b_mutbl, None))
sig: fn_ty_a.sig.clone(),
.. *fn_ty_b
});
- if_ok!(self.subtype(a_closure, b));
+ try!(self.subtype(a_closure, b));
Ok(Some(adj))
})
}
// check that the types which they point at are compatible
let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a);
- if_ok!(self.subtype(a_unsafe, b));
+ try!(self.subtype(a_unsafe, b));
// although references and unsafe ptrs have the same
// representation, we still register an AutoDerefRef so that
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ______________________________________________________________________
-// Type combining
+///////////////////////////////////////////////////////////////////////////
+// # Type combining
//
-// There are three type combiners: sub, lub, and glb. Each implements
-// the trait `Combine` and contains methods for combining two
-// instances of various things and yielding a new instance. These
-// combiner methods always yield a `result<T>`---failure is propagated
-// upward using `and_then()` methods. There is a lot of common code for
-// these operations, implemented as default methods on the `Combine`
-// trait.
+// There are four type combiners: equate, sub, lub, and glb. Each
+// implements the trait `Combine` and contains methods for combining
+// two instances of various things and yielding a new instance. These
+// combiner methods always yield a `Result<T>`. There is a lot of
+// common code for these operations, implemented as default methods on
+// the `Combine` trait.
//
-// In reality, the sub operation is rather different from lub/glb, but
-// they are combined into one trait to avoid duplication (they used to
-// be separate but there were many bugs because there were two copies
-// of most routines).
+// Each operation may have side-effects on the inference context,
+// though these can be unrolled using snapshots. On success, the
+// LUB/GLB operations return the appropriate bound. The Eq and Sub
+// operations generally return the first operand.
//
-// The differences are:
-//
-// - when making two things have a sub relationship, the order of the
-// arguments is significant (a <: b) and the return value of the
-// combine functions is largely irrelevant. The important thing is
-// whether the action succeeds or fails. If it succeeds, then side
-// effects have been committed into the type variables.
-//
-// - for GLB/LUB, the order of arguments is not significant (GLB(a,b) ==
-// GLB(b,a)) and the return value is important (it is the GLB). Of
-// course GLB/LUB may also have side effects.
-//
-// Contravariance
+// ## Contravariance
//
// When you are relating two things which have a contravariant
// relationship, you should use `contratys()` or `contraregions()`,
// rather than inversing the order of arguments! This is necessary
// because the order of arguments is not relevant for LUB and GLB. It
// is also useful to track which value is the "expected" value in
-// terms of error reporting, although we do not do that properly right
-// now.
+// terms of error reporting.
use middle::subst;
use middle::ty::{IntType, UintType};
use middle::ty::{BuiltinBounds};
use middle::ty;
-use middle::typeck::infer::{ToUres};
+use middle::typeck::infer::equate::Equate;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::unify::InferCtxtMethodsForSimplyUnifiableTypes;
-use middle::typeck::infer::{InferCtxt, cres, ures};
-use middle::typeck::infer::{TypeTrace};
-use util::common::indent;
+use middle::typeck::infer::{InferCtxt, cres};
+use middle::typeck::infer::{MiscVariable, TypeTrace};
+use middle::typeck::infer::type_variable::{RelationDir, EqTo,
+ SubtypeOf, SupertypeOf};
+use middle::ty_fold::{RegionFolder, TypeFoldable};
use util::ppaux::Repr;
use std::result;
fn a_is_expected(&self) -> bool;
fn trace(&self) -> TypeTrace;
+ fn equate<'a>(&'a self) -> Equate<'a>;
fn sub<'a>(&'a self) -> Sub<'a>;
fn lub<'a>(&'a self) -> Lub<'a>;
fn glb<'a>(&'a self) -> Glb<'a>;
try!(result::fold_(as_
.iter()
.zip(bs.iter())
- .map(|(a, b)| eq_tys(self, *a, *b))));
+ .map(|(a, b)| self.equate().tys(*a, *b))));
Ok(Vec::from_slice(as_))
}
for &space in subst::ParamSpace::all().iter() {
let a_tps = a_subst.types.get_slice(space);
let b_tps = b_subst.types.get_slice(space);
- let tps = if_ok!(self.tps(space, a_tps, b_tps));
+ let tps = try!(self.tps(space, a_tps, b_tps));
let a_regions = a_subst.regions().get_slice(space);
let b_regions = b_subst.regions().get_slice(space);
}
};
- let regions = if_ok!(relate_region_params(self,
- item_def_id,
- r_variances,
- a_regions,
- b_regions));
+ let regions = try!(relate_region_params(self,
+ item_def_id,
+ r_variances,
+ a_regions,
+ b_regions));
substs.types.replace(space, tps);
substs.mut_regions().replace(space, regions);
let b_r = b_rs[i];
let variance = variances[i];
let r = match variance {
- ty::Invariant => {
- eq_regions(this, a_r, b_r)
- .and_then(|()| Ok(a_r))
- }
+ ty::Invariant => this.equate().regions(a_r, b_r),
ty::Covariant => this.regions(a_r, b_r),
ty::Contravariant => this.contraregions(a_r, b_r),
ty::Bivariant => Ok(a_r),
};
- rs.push(if_ok!(r));
+ rs.push(try!(r));
}
Ok(rs)
}
fn bare_fn_tys(&self, a: &ty::BareFnTy,
b: &ty::BareFnTy) -> cres<ty::BareFnTy> {
- let fn_style = if_ok!(self.fn_styles(a.fn_style, b.fn_style));
- let abi = if_ok!(self.abi(a.abi, b.abi));
- let sig = if_ok!(self.fn_sigs(&a.sig, &b.sig));
+ let fn_style = try!(self.fn_styles(a.fn_style, b.fn_style));
+ let abi = try!(self.abi(a.abi, b.abi));
+ let sig = try!(self.fn_sigs(&a.sig, &b.sig));
Ok(ty::BareFnTy {fn_style: fn_style,
abi: abi,
sig: sig})
let store = match (a.store, b.store) {
(ty::RegionTraitStore(a_r, a_m),
ty::RegionTraitStore(b_r, b_m)) if a_m == b_m => {
- let r = if_ok!(self.contraregions(a_r, b_r));
+ let r = try!(self.contraregions(a_r, b_r));
ty::RegionTraitStore(r, a_m)
}
return Err(ty::terr_sigil_mismatch(expected_found(self, a.store, b.store)))
}
};
- let fn_style = if_ok!(self.fn_styles(a.fn_style, b.fn_style));
- let onceness = if_ok!(self.oncenesses(a.onceness, b.onceness));
- let bounds = if_ok!(self.existential_bounds(a.bounds, b.bounds));
- let sig = if_ok!(self.fn_sigs(&a.sig, &b.sig));
- let abi = if_ok!(self.abi(a.abi, b.abi));
+ let fn_style = try!(self.fn_styles(a.fn_style, b.fn_style));
+ let onceness = try!(self.oncenesses(a.onceness, b.onceness));
+ let bounds = try!(self.existential_bounds(a.bounds, b.bounds));
+ let sig = try!(self.fn_sigs(&a.sig, &b.sig));
+ let abi = try!(self.abi(a.abi, b.abi));
Ok(ty::ClosureTy {
fn_style: fn_style,
onceness: onceness,
Err(ty::terr_traits(
expected_found(self, a.def_id, b.def_id)))
} else {
- let substs = if_ok!(self.substs(a.def_id, &a.substs, &b.substs));
+ let substs = try!(self.substs(a.def_id, &a.substs, &b.substs));
Ok(ty::TraitRef { def_id: a.def_id,
substs: substs })
}
}
}
-pub fn eq_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> ures {
- let suber = this.sub();
- this.infcx().try(|| {
- suber.tys(a, b).and_then(|_ok| suber.contratys(a, b)).to_ures()
- })
-}
-
-pub fn eq_regions<C:Combine>(this: &C, a: ty::Region, b: ty::Region)
- -> ures {
- debug!("eq_regions({}, {})",
- a.repr(this.infcx().tcx),
- b.repr(this.infcx().tcx));
- let sub = this.sub();
- indent(|| {
- this.infcx().try(|| {
- sub.regions(a, b).and_then(|_r| sub.contraregions(a, b))
- }).or_else(|e| {
- // substitute a better error, but use the regions
- // found in the original error
- match e {
- ty::terr_regions_does_not_outlive(a1, b1) =>
- Err(ty::terr_regions_not_same(a1, b1)),
- _ => Err(e)
- }
- }).to_ures()
- })
-}
-
pub fn super_fn_sigs<C:Combine>(this: &C, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
fn argvecs<C:Combine>(this: &C, a_args: &[ty::t], b_args: &[ty::t]) -> cres<Vec<ty::t> > {
return Err(ty::terr_variadic_mismatch(expected_found(this, a.variadic, b.variadic)));
}
- let inputs = if_ok!(argvecs(this,
+ let inputs = try!(argvecs(this,
a.inputs.as_slice(),
b.inputs.as_slice()));
- let output = if_ok!(this.tys(a.output, b.output));
+ let output = try!(this.tys(a.output, b.output));
Ok(FnSig {binder_id: a.binder_id,
inputs: inputs,
output: output,
// Relate integral variables to other types
(&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => {
- if_ok!(this.infcx().simple_vars(this.a_is_expected(),
+ try!(this.infcx().simple_vars(this.a_is_expected(),
a_id, b_id));
Ok(a)
}
// Relate floating-point variables to other types
(&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => {
- if_ok!(this.infcx().simple_vars(this.a_is_expected(),
- a_id, b_id));
+ try!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id));
Ok(a)
}
(&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => {
(&ty::ty_bool, _) |
(&ty::ty_int(_), _) |
(&ty::ty_uint(_), _) |
- (&ty::ty_float(_), _) => {
+ (&ty::ty_float(_), _) |
+ (&ty::ty_err, _) => {
if ty::get(a).sty == ty::get(b).sty {
Ok(a)
} else {
(&ty::ty_enum(a_id, ref a_substs),
&ty::ty_enum(b_id, ref b_substs))
if a_id == b_id => {
- let substs = if_ok!(this.substs(a_id,
+ let substs = try!(this.substs(a_id,
a_substs,
b_substs));
Ok(ty::mk_enum(tcx, a_id, substs))
&ty::ty_trait(ref b_))
if a_.def_id == b_.def_id => {
debug!("Trying to match traits {:?} and {:?}", a, b);
- let substs = if_ok!(this.substs(a_.def_id, &a_.substs, &b_.substs));
- let bounds = if_ok!(this.existential_bounds(a_.bounds, b_.bounds));
+ let substs = try!(this.substs(a_.def_id, &a_.substs, &b_.substs));
+ let bounds = try!(this.existential_bounds(a_.bounds, b_.bounds));
Ok(ty::mk_trait(tcx,
a_.def_id,
substs.clone(),
(&ty::ty_struct(a_id, ref a_substs), &ty::ty_struct(b_id, ref b_substs))
if a_id == b_id => {
- let substs = if_ok!(this.substs(a_id, a_substs, b_substs));
+ let substs = try!(this.substs(a_id, a_substs, b_substs));
Ok(ty::mk_struct(tcx, a_id, substs))
}
(&ty::ty_unboxed_closure(a_id, a_region),
&ty::ty_unboxed_closure(b_id, b_region))
if a_id == b_id => {
- let region = if_ok!(this.regions(a_region, b_region));
+ // All ty_unboxed_closure types with the same id represent
+ // the (anonymous) type of the same closure expression. So
+ // all of their regions should be equated.
+ let region = try!(this.equate().regions(a_region, b_region));
Ok(ty::mk_unboxed_closure(tcx, a_id, region))
}
}
(&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
- let typ = if_ok!(this.tys(a_inner, b_inner));
+ let typ = try!(this.tys(a_inner, b_inner));
check_ptr_to_unsized(this, a, b, a_inner, b_inner, ty::mk_uniq(tcx, typ))
}
(&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
- let mt = if_ok!(this.mts(a_mt, b_mt));
+ let mt = try!(this.mts(a_mt, b_mt));
check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_ptr(tcx, mt))
}
(&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => {
- let r = if_ok!(this.contraregions(a_r, b_r));
+ let r = try!(this.contraregions(a_r, b_r));
// FIXME(14985) If we have mutable references to trait objects, we
// used to use covariant subtyping. I have preserved this behaviour,
// even though it is probably incorrect. So don't go down the usual
// path which would require invariance.
let mt = match (&ty::get(a_mt.ty).sty, &ty::get(b_mt.ty).sty) {
(&ty::ty_trait(..), &ty::ty_trait(..)) if a_mt.mutbl == b_mt.mutbl => {
- let ty = if_ok!(this.tys(a_mt.ty, b_mt.ty));
+ let ty = try!(this.tys(a_mt.ty, b_mt.ty));
ty::mt { ty: ty, mutbl: a_mt.mutbl }
}
- _ => if_ok!(this.mts(a_mt, b_mt))
+ _ => try!(this.mts(a_mt, b_mt))
};
check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_rptr(tcx, r, mt))
}
vid: ty::IntVid,
val: ty::IntVarValue) -> cres<ty::t>
{
- if_ok!(this.infcx().simple_var_t(vid_is_expected, vid, val));
+ try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
match val {
IntType(v) => Ok(ty::mk_mach_int(v)),
UintType(v) => Ok(ty::mk_mach_uint(v))
vid: ty::FloatVid,
val: ast::FloatTy) -> cres<ty::t>
{
- if_ok!(this.infcx().simple_var_t(vid_is_expected, vid, val));
+ try!(this.infcx().simple_var_t(vid_is_expected, vid, val));
Ok(ty::mk_mach_float(val))
}
}
+
+impl<'f> CombineFields<'f> {
+ pub fn switch_expected(&self) -> CombineFields<'f> {
+ CombineFields {
+ a_is_expected: !self.a_is_expected,
+ ..(*self).clone()
+ }
+ }
+
+ fn equate(&self) -> Equate<'f> {
+ Equate((*self).clone())
+ }
+
+ fn sub(&self) -> Sub<'f> {
+ Sub((*self).clone())
+ }
+
+ pub fn instantiate(&self,
+ a_ty: ty::t,
+ dir: RelationDir,
+ b_vid: ty::TyVid)
+ -> cres<()>
+ {
+ let tcx = self.infcx.tcx;
+ let mut stack = Vec::new();
+ stack.push((a_ty, dir, b_vid));
+ loop {
+ // For each turn of the loop, we extract a tuple
+ //
+ // (a_ty, dir, b_vid)
+ //
+ // to relate. Here dir is either SubtypeOf or
+ // SupertypeOf. The idea is that we should ensure that
+ // the type `a_ty` is a subtype or supertype (respectively) of the
+ // type to which `b_vid` is bound.
+ //
+ // If `b_vid` has not yet been instantiated with a type
+ // (which is always true on the first iteration, but not
+ // necessarily true on later iterations), we will first
+ // instantiate `b_vid` with a *generalized* version of
+ // `a_ty`. Generalization introduces other inference
+ // variables wherever subtyping could occur (at time of
+ // this writing, this means replacing free regions with
+ // region variables).
+ let (a_ty, dir, b_vid) = match stack.pop() {
+ None => break,
+ Some(e) => e,
+ };
+
+ debug!("instantiate(a_ty={} dir={} b_vid={})",
+ a_ty.repr(tcx),
+ dir,
+ b_vid.repr(tcx));
+
+ // Check whether `vid` has been instantiated yet. If not,
+ // make a generalized form of `ty` and instantiate with
+ // that.
+ let b_ty = self.infcx.type_variables.borrow().probe(b_vid);
+ let b_ty = match b_ty {
+ Some(t) => t, // ...already instantiated.
+ None => { // ...not yet instantiated:
+ // Generalize type if necessary.
+ let generalized_ty = match dir {
+ EqTo => a_ty,
+ SupertypeOf | SubtypeOf => self.generalize(a_ty)
+ };
+ debug!("instantiate(a_ty={}, dir={}, \
+ b_vid={}, generalized_ty={})",
+ a_ty.repr(tcx), dir, b_vid.repr(tcx),
+ generalized_ty.repr(tcx));
+ self.infcx.type_variables
+ .borrow_mut()
+ .instantiate_and_push(
+ b_vid, generalized_ty, &mut stack);
+ generalized_ty
+ }
+ };
+
+ // The original triple was `(a_ty, dir, b_vid)` -- now we have
+ // resolved `b_vid` to `b_ty`, so apply `(a_ty, dir, b_ty)`:
+ //
+ // FIXME(#16847): This code is non-ideal because all these subtype
+ // relations wind up attributed to the same spans. We need
+ // to associate causes/spans with each of the relations in
+ // the stack to get this right.
+ match dir {
+ EqTo => {
+ try!(self.equate().tys(a_ty, b_ty));
+ }
+
+ SubtypeOf => {
+ try!(self.sub().tys(a_ty, b_ty));
+ }
+
+ SupertypeOf => {
+ try!(self.sub().contratys(a_ty, b_ty));
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ fn generalize(&self, t: ty::t) -> ty::t {
+ // FIXME(#16847): This is non-ideal because we don't give a
+ // very descriptive origin for this region variable.
+
+ let infcx = self.infcx;
+ let span = self.trace.origin.span();
+ t.fold_with(
+ &mut RegionFolder::regions(
+ self.infcx.tcx,
+ |_| infcx.next_region_var(MiscVariable(span))))
+ }
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use middle::ty::{BuiltinBounds};
+use middle::ty;
+use middle::ty::TyVar;
+use middle::typeck::infer::combine::*;
+use middle::typeck::infer::{cres};
+use middle::typeck::infer::glb::Glb;
+use middle::typeck::infer::InferCtxt;
+use middle::typeck::infer::lub::Lub;
+use middle::typeck::infer::sub::Sub;
+use middle::typeck::infer::{TypeTrace, Subtype};
+use middle::typeck::infer::type_variable::{EqTo};
+use util::ppaux::{Repr};
+
+use syntax::ast::{Onceness, FnStyle};
+
+pub struct Equate<'f> {
+ fields: CombineFields<'f>
+}
+
+#[allow(non_snake_case)]
+pub fn Equate<'f>(cf: CombineFields<'f>) -> Equate<'f> {
+ Equate { fields: cf }
+}
+
+impl<'f> Combine for Equate<'f> {
+ fn infcx<'a>(&'a self) -> &'a InferCtxt<'a> { self.fields.infcx }
+ fn tag(&self) -> String { "eq".to_string() }
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn trace(&self) -> TypeTrace { self.fields.trace.clone() }
+
+ fn equate<'a>(&'a self) -> Equate<'a> { Equate(self.fields.clone()) }
+ fn sub<'a>(&'a self) -> Sub<'a> { Sub(self.fields.clone()) }
+ fn lub<'a>(&'a self) -> Lub<'a> { Lub(self.fields.clone()) }
+ fn glb<'a>(&'a self) -> Glb<'a> { Glb(self.fields.clone()) }
+
+ fn contratys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
+ self.tys(a, b)
+ }
+
+ fn contraregions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
+ self.regions(a, b)
+ }
+
+ fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
+ debug!("{}.regions({}, {})",
+ self.tag(),
+ a.repr(self.fields.infcx.tcx),
+ b.repr(self.fields.infcx.tcx));
+ self.infcx().region_vars.make_eqregion(Subtype(self.trace()), a, b);
+ Ok(a)
+ }
+
+ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
+ debug!("mts({} <: {})",
+ a.repr(self.fields.infcx.tcx),
+ b.repr(self.fields.infcx.tcx));
+
+ if a.mutbl != b.mutbl { return Err(ty::terr_mutability); }
+ let t = try!(self.tys(a.ty, b.ty));
+ Ok(ty::mt { mutbl: a.mutbl, ty: t })
+ }
+
+ fn fn_styles(&self, a: FnStyle, b: FnStyle) -> cres<FnStyle> {
+ if a != b {
+ Err(ty::terr_fn_style_mismatch(expected_found(self, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+
+ fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness> {
+ if a != b {
+ Err(ty::terr_onceness_mismatch(expected_found(self, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+
+ fn builtin_bounds(&self,
+ a: BuiltinBounds,
+ b: BuiltinBounds)
+ -> cres<BuiltinBounds>
+ {
+ // More bounds is a subtype of fewer bounds.
+ //
+ // e.g., fn:Copy() <: fn(), because the former is a function
+ // that only closes over copyable things, but the latter is
+ // any function at all.
+ if a != b {
+ Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+
+ fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
+ debug!("{}.tys({}, {})", self.tag(),
+ a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
+ if a == b { return Ok(a); }
+
+ let infcx = self.fields.infcx;
+ let a = infcx.type_variables.borrow().replace_if_possible(a);
+ let b = infcx.type_variables.borrow().replace_if_possible(b);
+ match (&ty::get(a).sty, &ty::get(b).sty) {
+ (&ty::ty_bot, &ty::ty_bot) => {
+ Ok(a)
+ }
+
+ (&ty::ty_bot, _) |
+ (_, &ty::ty_bot) => {
+ Err(ty::terr_sorts(expected_found(self, a, b)))
+ }
+
+ (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
+ infcx.type_variables.borrow_mut().relate_vars(a_id, EqTo, b_id);
+ Ok(a)
+ }
+
+ (&ty::ty_infer(TyVar(a_id)), _) => {
+ try!(self.fields.instantiate(b, EqTo, a_id));
+ Ok(a)
+ }
+
+ (_, &ty::ty_infer(TyVar(b_id))) => {
+ try!(self.fields.instantiate(a, EqTo, b_id));
+ Ok(a)
+ }
+
+ _ => {
+ super_tys(self, a, b)
+ }
+ }
+ }
+
+ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
+ try!(self.sub().fn_sigs(a, b));
+ self.sub().fn_sigs(b, a)
+ }
+}
sub,
"");
}
+ infer::ProcCapture(span, id) => {
+ self.tcx.sess.span_err(
+ span,
+ format!("captured variable `{}` must be 'static \
+ to be captured in a proc",
+ ty::local_var_name_str(self.tcx, id).get())
+ .as_slice());
+ note_and_explain_region(
+ self.tcx,
+ "captured variable is only valid for ",
+ sup,
+ "");
+ }
infer::IndexSlice(span) => {
self.tcx.sess.span_err(span,
"index of slice outside its lifetime");
bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
}
infer::EarlyBoundRegion(_, name) => {
- format!(" for lifetime parameter `{}",
+ format!(" for lifetime parameter `{}`",
token::get_name(name).get())
}
infer::BoundRegionInCoherence(name) => {
- format!(" for lifetime parameter `{} in coherence check",
+ format!(" for lifetime parameter `{}` in coherence check",
token::get_name(name).get())
}
infer::UpvarRegion(ref upvar_id, _) => {
self.tcx,
id).get().to_string()).as_slice());
}
+ infer::ProcCapture(span, id) => {
+ self.tcx.sess.span_note(
+ span,
+ format!("...so that captured variable `{}` \
+ is 'static",
+ ty::local_var_name_str(
+ self.tcx,
+ id).get()).as_slice());
+ }
infer::IndexSlice(span) => {
self.tcx.sess.span_note(
span,
infer::AutoBorrow(span) => {
self.tcx.sess.span_note(
span,
- "...so that reference is valid \
- at the time of implicit borrow");
+ "...so that auto-reference is valid \
+ at the time of borrow");
}
infer::ExprTypeIsNotInScope(t, span) => {
self.tcx.sess.span_note(
use middle::ty::{BuiltinBounds};
use middle::ty::RegionVid;
use middle::ty;
-use middle::typeck::infer::then;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::lattice::*;
+use middle::typeck::infer::equate::Equate;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::{cres, InferCtxt};
use util::ppaux::mt_to_string;
use util::ppaux::Repr;
-pub struct Glb<'f>(pub CombineFields<'f>); // "greatest lower bound" (common subtype)
+/// "Greatest lower bound" (common subtype)
+pub struct Glb<'f> {
+ fields: CombineFields<'f>
+}
-impl<'f> Glb<'f> {
- pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> { let Glb(ref v) = *self; v }
+#[allow(non_snake_case)]
+pub fn Glb<'f>(cf: CombineFields<'f>) -> Glb<'f> {
+ Glb { fields: cf }
}
impl<'f> Combine for Glb<'f> {
- fn infcx<'a>(&'a self) -> &'a InferCtxt<'a> { self.get_ref().infcx }
+ fn infcx<'a>(&'a self) -> &'a InferCtxt<'a> { self.fields.infcx }
fn tag(&self) -> String { "glb".to_string() }
- fn a_is_expected(&self) -> bool { self.get_ref().a_is_expected }
- fn trace(&self) -> TypeTrace { self.get_ref().trace.clone() }
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn trace(&self) -> TypeTrace { self.fields.trace.clone() }
- fn sub<'a>(&'a self) -> Sub<'a> { Sub(self.get_ref().clone()) }
- fn lub<'a>(&'a self) -> Lub<'a> { Lub(self.get_ref().clone()) }
- fn glb<'a>(&'a self) -> Glb<'a> { Glb(self.get_ref().clone()) }
+ fn equate<'a>(&'a self) -> Equate<'a> { Equate(self.fields.clone()) }
+ fn sub<'a>(&'a self) -> Sub<'a> { Sub(self.fields.clone()) }
+ fn lub<'a>(&'a self) -> Lub<'a> { Lub(self.fields.clone()) }
+ fn glb<'a>(&'a self) -> Glb<'a> { Glb(self.fields.clone()) }
fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
- let tcx = self.get_ref().infcx.tcx;
+ let tcx = self.fields.infcx.tcx;
debug!("{}.mts({}, {})",
self.tag(),
mt_to_string(tcx, b));
match (a.mutbl, b.mutbl) {
- // If one side or both is mut, then the GLB must use
- // the precise type from the mut side.
- (MutMutable, MutMutable) => {
- eq_tys(self, a.ty, b.ty).then(|| {
- Ok(ty::mt {ty: a.ty, mutbl: MutMutable})
- })
- }
-
- // If one side or both is immutable, we can use the GLB of
- // both sides but mutbl must be `MutImmutable`.
- (MutImmutable, MutImmutable) => {
- self.tys(a.ty, b.ty).and_then(|t| {
+ // If one side or both is mut, then the GLB must use
+ // the precise type from the mut side.
+ (MutMutable, MutMutable) => {
+ let t = try!(self.equate().tys(a.ty, b.ty));
+ Ok(ty::mt {ty: t, mutbl: MutMutable})
+ }
+
+ // If one side or both is immutable, we can use the GLB of
+ // both sides but mutbl must be `MutImmutable`.
+ (MutImmutable, MutImmutable) => {
+ let t = try!(self.tys(a.ty, b.ty));
Ok(ty::mt {ty: t, mutbl: MutImmutable})
- })
- }
-
- // There is no mutual subtype of these combinations.
- (MutMutable, MutImmutable) |
- (MutImmutable, MutMutable) => {
- Err(ty::terr_mutability)
- }
+ }
+
+ // There is no mutual subtype of these combinations.
+ (MutMutable, MutImmutable) |
+ (MutImmutable, MutMutable) => {
+ Err(ty::terr_mutability)
+ }
}
}
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
debug!("{}.regions({:?}, {:?})",
self.tag(),
- a.repr(self.get_ref().infcx.tcx),
- b.repr(self.get_ref().infcx.tcx));
+ a.repr(self.fields.infcx.tcx),
+ b.repr(self.fields.infcx.tcx));
- Ok(self.get_ref().infcx.region_vars.glb_regions(Subtype(self.trace()), a, b))
+ Ok(self.fields.infcx.region_vars.glb_regions(Subtype(self.trace()), a, b))
}
fn contraregions(&self, a: ty::Region, b: ty::Region)
// please see the large comment in `region_inference.rs`.
debug!("{}.fn_sigs({:?}, {:?})",
- self.tag(), a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
+ self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
let _indenter = indenter();
// Make a mark so we can examine "all bindings that were
// created as part of this type comparison".
- let mark = self.get_ref().infcx.region_vars.mark();
+ let mark = self.fields.infcx.region_vars.mark();
// Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_map) =
- self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions(
+ self.fields.infcx.replace_late_bound_regions_with_fresh_regions(
self.trace(), a);
let a_vars = var_ids(self, &a_map);
let (b_with_fresh, b_map) =
- self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions(
+ self.fields.infcx.replace_late_bound_regions_with_fresh_regions(
self.trace(), b);
let b_vars = var_ids(self, &b_map);
// Collect constraints.
- let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
- debug!("sig0 = {}", sig0.repr(self.get_ref().infcx.tcx));
+ let sig0 = try!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
+ debug!("sig0 = {}", sig0.repr(self.fields.infcx.tcx));
// Generalize the regions appearing in fn_ty0 if possible
let new_vars =
- self.get_ref().infcx.region_vars.vars_created_since_mark(mark);
+ self.fields.infcx.region_vars.vars_created_since_mark(mark);
let sig1 =
fold_regions_in_sig(
- self.get_ref().infcx.tcx,
+ self.fields.infcx.tcx,
&sig0,
|r| {
generalize_region(self,
b_vars.as_slice(),
r)
});
- debug!("sig1 = {}", sig1.repr(self.get_ref().infcx.tcx));
+ debug!("sig1 = {}", sig1.repr(self.fields.infcx.tcx));
return Ok(sig1);
fn generalize_region(this: &Glb,
return r0;
}
- let tainted = this.get_ref().infcx.region_vars.tainted(mark, r0);
+ let tainted = this.fields.infcx.region_vars.tainted(mark, r0);
let mut a_r = None;
let mut b_r = None;
return ty::ReLateBound(new_binder_id, *a_br);
}
}
- this.get_ref().infcx.tcx.sess.span_bug(
- this.get_ref().trace.origin.span(),
+ this.fields.infcx.tcx.sess.span_bug(
+ this.fields.trace.origin.span(),
format!("could not find original bound region for {:?}",
r).as_slice())
}
fn fresh_bound_variable(this: &Glb, binder_id: NodeId) -> ty::Region {
- this.get_ref().infcx.region_vars.new_bound(binder_id)
+ this.fields.infcx.region_vars.new_bound(binder_id)
}
}
}
// except according to those terms.
/*!
- *
* # Lattice Variables
*
* This file contains generic code for operating on inference variables
use middle::ty::{RegionVid, TyVar};
use middle::ty;
-use middle::typeck::infer::{ToUres};
use middle::typeck::infer::*;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lub::Lub;
-use middle::typeck::infer::unify::*;
-use middle::typeck::infer::sub::Sub;
use util::ppaux::Repr;
use std::collections::HashMap;
-trait LatticeValue : Clone + Repr + PartialEq {
- fn sub(cf: CombineFields, a: &Self, b: &Self) -> ures;
- fn lub(cf: CombineFields, a: &Self, b: &Self) -> cres<Self>;
- fn glb(cf: CombineFields, a: &Self, b: &Self) -> cres<Self>;
-}
-
-pub type LatticeOp<'a, T> =
- |cf: CombineFields, a: &T, b: &T|: 'a -> cres<T>;
-
-impl LatticeValue for ty::t {
- fn sub(cf: CombineFields, a: &ty::t, b: &ty::t) -> ures {
- Sub(cf).tys(*a, *b).to_ures()
- }
-
- fn lub(cf: CombineFields, a: &ty::t, b: &ty::t) -> cres<ty::t> {
- Lub(cf).tys(*a, *b)
- }
-
- fn glb(cf: CombineFields, a: &ty::t, b: &ty::t) -> cres<ty::t> {
- Glb(cf).tys(*a, *b)
- }
-}
-
-pub trait CombineFieldsLatticeMethods<T:LatticeValue, K:UnifyKey<Bounds<T>>> {
- /// make variable a subtype of variable
- fn var_sub_var(&self,
- a_id: K,
- b_id: K)
- -> ures;
-
- /// make variable a subtype of T
- fn var_sub_t(&self,
- a_id: K,
- b: T)
- -> ures;
-
- /// make T a subtype of variable
- fn t_sub_var(&self,
- a: T,
- b_id: K)
- -> ures;
-
- fn set_var_to_merged_bounds(&self,
- v_id: K,
- a: &Bounds<T>,
- b: &Bounds<T>,
- rank: uint)
- -> ures;
-}
-
-pub trait CombineFieldsLatticeMethods2<T:LatticeValue> {
- fn merge_bnd(&self,
- a: &Bound<T>,
- b: &Bound<T>,
- lattice_op: LatticeOp<T>)
- -> cres<Bound<T>>;
-
- fn bnds(&self, a: &Bound<T>, b: &Bound<T>) -> ures;
-}
-
-impl<'f,T:LatticeValue, K:UnifyKey<Bounds<T>>>
- CombineFieldsLatticeMethods<T,K> for CombineFields<'f>
-{
- fn var_sub_var(&self,
- a_id: K,
- b_id: K)
- -> ures
- {
- /*!
- * Make one variable a subtype of another variable. This is a
- * subtle and tricky process, as described in detail at the
- * top of infer.rs.
- */
-
- let tcx = self.infcx.tcx;
- let table = UnifyKey::unification_table(self.infcx);
-
- // Need to make sub_id a subtype of sup_id.
- let node_a = table.borrow_mut().get(tcx, a_id);
- let node_b = table.borrow_mut().get(tcx, b_id);
- let a_id = node_a.key.clone();
- let b_id = node_b.key.clone();
- let a_bounds = node_a.value.clone();
- let b_bounds = node_b.value.clone();
-
- debug!("vars({}={} <: {}={})",
- a_id, a_bounds.repr(tcx),
- b_id, b_bounds.repr(tcx));
-
- if a_id == b_id { return Ok(()); }
-
- // If both A's UB and B's LB have already been bound to types,
- // see if we can make those types subtypes.
- match (&a_bounds.ub, &b_bounds.lb) {
- (&Some(ref a_ub), &Some(ref b_lb)) => {
- let r = self.infcx.try(
- || LatticeValue::sub(self.clone(), a_ub, b_lb));
- match r {
- Ok(()) => {
- return Ok(());
- }
- Err(_) => { /*fallthrough */ }
- }
- }
- _ => { /*fallthrough*/ }
- }
-
- // Otherwise, we need to merge A and B so as to guarantee that
- // A remains a subtype of B. Actually, there are other options,
- // but that's the route we choose to take.
-
- let (new_root, new_rank) =
- table.borrow_mut().unify(tcx, &node_a, &node_b);
- self.set_var_to_merged_bounds(new_root,
- &a_bounds, &b_bounds,
- new_rank)
- }
-
- /// make variable a subtype of T
- fn var_sub_t(&self,
- a_id: K,
- b: T)
- -> ures
- {
- /*!
- * Make a variable (`a_id`) a subtype of the concrete type `b`.
- */
-
- let tcx = self.infcx.tcx;
- let table = UnifyKey::unification_table(self.infcx);
- let node_a = table.borrow_mut().get(tcx, a_id);
- let a_id = node_a.key.clone();
- let a_bounds = &node_a.value;
- let b_bounds = &Bounds { lb: None, ub: Some(b.clone()) };
-
- debug!("var_sub_t({}={} <: {})",
- a_id,
- a_bounds.repr(self.infcx.tcx),
- b.repr(self.infcx.tcx));
-
- self.set_var_to_merged_bounds(
- a_id, a_bounds, b_bounds, node_a.rank)
- }
-
- fn t_sub_var(&self,
- a: T,
- b_id: K)
- -> ures
- {
- /*!
- * Make a concrete type (`a`) a subtype of the variable `b_id`
- */
-
- let tcx = self.infcx.tcx;
- let table = UnifyKey::unification_table(self.infcx);
- let a_bounds = &Bounds { lb: Some(a.clone()), ub: None };
- let node_b = table.borrow_mut().get(tcx, b_id);
- let b_id = node_b.key.clone();
- let b_bounds = &node_b.value;
-
- debug!("t_sub_var({} <: {}={})",
- a.repr(self.infcx.tcx),
- b_id,
- b_bounds.repr(self.infcx.tcx));
-
- self.set_var_to_merged_bounds(
- b_id, a_bounds, b_bounds, node_b.rank)
- }
-
- fn set_var_to_merged_bounds(&self,
- v_id: K,
- a: &Bounds<T>,
- b: &Bounds<T>,
- rank: uint)
- -> ures
- {
- /*!
- * Updates the bounds for the variable `v_id` to be the intersection
- * of `a` and `b`. That is, the new bounds for `v_id` will be
- * a bounds c such that:
- * c.ub <: a.ub
- * c.ub <: b.ub
- * a.lb <: c.lb
- * b.lb <: c.lb
- * If this cannot be achieved, the result is failure.
- */
-
- // Think of the two diamonds, we want to find the
- // intersection. There are basically four possibilities (you
- // can swap A/B in these pictures):
- //
- // A A
- // / \ / \
- // / B \ / B \
- // / / \ \ / / \ \
- // * * * * * / * *
- // \ \ / / \ / /
- // \ B / / \ / /
- // \ / * \ /
- // A \ / A
- // B
-
- let tcx = self.infcx.tcx;
- let table = UnifyKey::unification_table(self.infcx);
-
- debug!("merge({},{},{})",
- v_id,
- a.repr(self.infcx.tcx),
- b.repr(self.infcx.tcx));
-
- // First, relate the lower/upper bounds of A and B.
- // Note that these relations *must* hold for us
- // to be able to merge A and B at all, and relating
- // them explicitly gives the type inferencer more
- // information and helps to produce tighter bounds
- // when necessary.
- let () = if_ok!(self.bnds(&a.lb, &b.ub));
- let () = if_ok!(self.bnds(&b.lb, &a.ub));
- let ub = if_ok!(self.merge_bnd(&a.ub, &b.ub, LatticeValue::glb));
- let lb = if_ok!(self.merge_bnd(&a.lb, &b.lb, LatticeValue::lub));
- let bounds = Bounds { lb: lb, ub: ub };
- debug!("merge({}): bounds={}",
- v_id,
- bounds.repr(self.infcx.tcx));
-
- // the new bounds must themselves
- // be relatable:
- let () = if_ok!(self.bnds(&bounds.lb, &bounds.ub));
- table.borrow_mut().set(tcx, v_id, Root(bounds, rank));
- Ok(())
- }
-}
-
-impl<'f,T:LatticeValue>
- CombineFieldsLatticeMethods2<T> for CombineFields<'f>
-{
- fn merge_bnd(&self,
- a: &Bound<T>,
- b: &Bound<T>,
- lattice_op: LatticeOp<T>)
- -> cres<Bound<T>>
- {
- /*!
- * Combines two bounds into a more general bound.
- */
-
- debug!("merge_bnd({},{})",
- a.repr(self.infcx.tcx),
- b.repr(self.infcx.tcx));
- match (a, b) {
- (&None, &None) => Ok(None),
- (&Some(_), &None) => Ok((*a).clone()),
- (&None, &Some(_)) => Ok((*b).clone()),
- (&Some(ref v_a), &Some(ref v_b)) => {
- lattice_op(self.clone(), v_a, v_b).and_then(|v| Ok(Some(v)))
- }
- }
- }
-
- fn bnds(&self,
- a: &Bound<T>,
- b: &Bound<T>)
- -> ures
- {
- debug!("bnds({} <: {})",
- a.repr(self.infcx.tcx),
- b.repr(self.infcx.tcx));
-
- match (a, b) {
- (&None, &None) |
- (&Some(_), &None) |
- (&None, &Some(_)) => {
- Ok(())
- }
- (&Some(ref t_a), &Some(ref t_b)) => {
- LatticeValue::sub(self.clone(), t_a, t_b)
- }
- }
- }
-}
-
-// ______________________________________________________________________
-// Lattice operations on variables
-//
-// This is common code used by both LUB and GLB to compute the LUB/GLB
-// for pairs of variables or for variables and values.
-
pub trait LatticeDir {
- fn combine_fields<'a>(&'a self) -> CombineFields<'a>;
- fn bnd<T:Clone>(&self, b: &Bounds<T>) -> Option<T>;
- fn with_bnd<T:Clone>(&self, b: &Bounds<T>, t: T) -> Bounds<T>;
-}
-
-pub trait TyLatticeDir {
+ // Relates the bottom type to `t` and returns LUB(t, _|_) or
+ // GLB(t, _|_) as appropriate.
fn ty_bot(&self, t: ty::t) -> cres<ty::t>;
-}
-impl<'f> LatticeDir for Lub<'f> {
- fn combine_fields<'a>(&'a self) -> CombineFields<'a> { self.get_ref().clone() }
- fn bnd<T:Clone>(&self, b: &Bounds<T>) -> Option<T> { b.ub.clone() }
- fn with_bnd<T:Clone>(&self, b: &Bounds<T>, t: T) -> Bounds<T> {
- Bounds { ub: Some(t), ..(*b).clone() }
- }
+ // Relates the type `v` to `a` and `b` such that `v` represents
+ // the LUB/GLB of `a` and `b` as appropriate.
+ fn relate_bound<'a>(&'a self, v: ty::t, a: ty::t, b: ty::t) -> cres<()>;
}
-impl<'f> TyLatticeDir for Lub<'f> {
+impl<'a> LatticeDir for Lub<'a> {
fn ty_bot(&self, t: ty::t) -> cres<ty::t> {
Ok(t)
}
-}
-impl<'f> LatticeDir for Glb<'f> {
- fn combine_fields<'a>(&'a self) -> CombineFields<'a> { self.get_ref().clone() }
- fn bnd<T:Clone>(&self, b: &Bounds<T>) -> Option<T> { b.lb.clone() }
- fn with_bnd<T:Clone>(&self, b: &Bounds<T>, t: T) -> Bounds<T> {
- Bounds { lb: Some(t), ..(*b).clone() }
+ fn relate_bound<'a>(&'a self, v: ty::t, a: ty::t, b: ty::t) -> cres<()> {
+ let sub = self.sub();
+ try!(sub.tys(a, v));
+ try!(sub.tys(b, v));
+ Ok(())
}
}
-impl<'f> TyLatticeDir for Glb<'f> {
- fn ty_bot(&self, _t: ty::t) -> cres<ty::t> {
+impl<'a> LatticeDir for Glb<'a> {
+ fn ty_bot(&self, _: ty::t) -> cres<ty::t> {
Ok(ty::mk_bot())
}
+
+ fn relate_bound<'a>(&'a self, v: ty::t, a: ty::t, b: ty::t) -> cres<()> {
+ let sub = self.sub();
+ try!(sub.tys(v, a));
+ try!(sub.tys(v, b));
+ Ok(())
+ }
}
-pub fn super_lattice_tys<L:LatticeDir+TyLatticeDir+Combine>(this: &L,
- a: ty::t,
- b: ty::t)
- -> cres<ty::t> {
+pub fn super_lattice_tys<L:LatticeDir+Combine>(this: &L,
+ a: ty::t,
+ b: ty::t)
+ -> cres<ty::t>
+{
debug!("{}.lattice_tys({}, {})",
this.tag(),
a.repr(this.infcx().tcx),
return Ok(a);
}
- let tcx = this.infcx().tcx;
-
+ let infcx = this.infcx();
+ let a = infcx.type_variables.borrow().replace_if_possible(a);
+ let b = infcx.type_variables.borrow().replace_if_possible(b);
match (&ty::get(a).sty, &ty::get(b).sty) {
- (&ty::ty_bot, _) => { return this.ty_bot(b); }
- (_, &ty::ty_bot) => { return this.ty_bot(a); }
-
- (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
- let r = if_ok!(lattice_vars(this, a_id, b_id,
- |x, y| this.tys(*x, *y)));
- return match r {
- VarResult(v) => Ok(ty::mk_var(tcx, v)),
- ValueResult(t) => Ok(t)
- };
- }
-
- (&ty::ty_infer(TyVar(a_id)), _) => {
- return lattice_var_and_t(this, a_id, &b,
- |x, y| this.tys(*x, *y));
- }
-
- (_, &ty::ty_infer(TyVar(b_id))) => {
- return lattice_var_and_t(this, b_id, &a,
- |x, y| this.tys(*x, *y));
+ (&ty::ty_bot, _) => { this.ty_bot(b) }
+ (_, &ty::ty_bot) => { this.ty_bot(a) }
+
+ (&ty::ty_infer(TyVar(..)), _) |
+ (_, &ty::ty_infer(TyVar(..))) => {
+ let v = infcx.next_ty_var();
+ try!(this.relate_bound(v, a, b));
+ Ok(v)
}
_ => {
- return super_tys(this, a, b);
- }
- }
-}
-
-pub type LatticeDirOp<'a, T> = |a: &T, b: &T|: 'a -> cres<T>;
-
-#[deriving(Clone)]
-pub enum LatticeVarResult<K,T> {
- VarResult(K),
- ValueResult(T)
-}
-
-/**
- * Computes the LUB or GLB of two bounded variables. These could be any
- * sort of variables, but in the comments on this function I'll assume
- * we are doing an LUB on two type variables.
- *
- * This computation can be done in one of two ways:
- *
- * - If both variables have an upper bound, we may just compute the
- * LUB of those bounds and return that, in which case we are
- * returning a type. This is indicated with a `ValueResult` return.
- *
- * - If the variables do not both have an upper bound, we will unify
- * the variables and return the unified variable, in which case the
- * result is a variable. This is indicated with a `VarResult`
- * return. */
-pub fn lattice_vars<L:LatticeDir+Combine,
- T:LatticeValue,
- K:UnifyKey<Bounds<T>>>(
- this: &L, // defines whether we want LUB or GLB
- a_vid: K, // first variable
- b_vid: K, // second variable
- lattice_dir_op: LatticeDirOp<T>) // LUB or GLB operation on types
- -> cres<LatticeVarResult<K,T>>
-{
- let tcx = this.infcx().tcx;
- let table = UnifyKey::unification_table(this.infcx());
-
- let node_a = table.borrow_mut().get(tcx, a_vid);
- let node_b = table.borrow_mut().get(tcx, b_vid);
- let a_vid = node_a.key.clone();
- let b_vid = node_b.key.clone();
- let a_bounds = &node_a.value;
- let b_bounds = &node_b.value;
-
- debug!("{}.lattice_vars({}={} <: {}={})",
- this.tag(),
- a_vid, a_bounds.repr(tcx),
- b_vid, b_bounds.repr(tcx));
-
- // Same variable: the easy case.
- if a_vid == b_vid {
- return Ok(VarResult(a_vid));
- }
-
- // If both A and B have an UB type, then we can just compute the
- // LUB of those types:
- let (a_bnd, b_bnd) = (this.bnd(a_bounds), this.bnd(b_bounds));
- match (a_bnd, b_bnd) {
- (Some(ref a_ty), Some(ref b_ty)) => {
- match this.infcx().try(|| lattice_dir_op(a_ty, b_ty) ) {
- Ok(t) => return Ok(ValueResult(t)),
- Err(_) => { /*fallthrough */ }
- }
- }
- _ => {/*fallthrough*/}
- }
-
- // Otherwise, we need to merge A and B into one variable. We can
- // then use either variable as an upper bound:
- let cf = this.combine_fields();
- let () = try!(cf.var_sub_var(a_vid.clone(), b_vid.clone()));
- Ok(VarResult(a_vid.clone()))
-}
-
-pub fn lattice_var_and_t<L:LatticeDir+Combine,
- T:LatticeValue,
- K:UnifyKey<Bounds<T>>>(
- this: &L,
- a_id: K,
- b: &T,
- lattice_dir_op: LatticeDirOp<T>)
- -> cres<T>
-{
- let tcx = this.infcx().tcx;
- let table = UnifyKey::unification_table(this.infcx());
-
- let node_a = table.borrow_mut().get(tcx, a_id);
- let a_id = node_a.key.clone();
- let a_bounds = &node_a.value;
-
- // The comments in this function are written for LUB, but they
- // apply equally well to GLB if you inverse upper/lower/sub/super/etc.
-
- debug!("{}.lattice_var_and_t({}={} <: {})",
- this.tag(),
- a_id,
- a_bounds.repr(this.infcx().tcx),
- b.repr(this.infcx().tcx));
-
- match this.bnd(a_bounds) {
- Some(ref a_bnd) => {
- // If a has an upper bound, return the LUB(a.ub, b)
- debug!("bnd=Some({})", a_bnd.repr(this.infcx().tcx));
- lattice_dir_op(a_bnd, b)
- }
- None => {
- // If a does not have an upper bound, make b the upper bound of a
- // and then return b.
- debug!("bnd=None");
- let a_bounds = this.with_bnd(a_bounds, (*b).clone());
- let () = try!(this.combine_fields().bnds(&a_bounds.lb,
- &a_bounds.ub));
- table.borrow_mut().set(tcx,
- a_id.clone(),
- Root(a_bounds.clone(), node_a.rank));
- Ok((*b).clone())
+ super_tys(this, a, b)
}
}
}
-// ___________________________________________________________________________
+///////////////////////////////////////////////////////////////////////////
// Random utility functions used by LUB/GLB when computing LUB/GLB of
// fn types
use middle::ty::{BuiltinBounds};
use middle::ty::RegionVid;
use middle::ty;
-use middle::typeck::infer::then;
use middle::typeck::infer::combine::*;
+use middle::typeck::infer::equate::Equate;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lattice::*;
use middle::typeck::infer::sub::Sub;
use util::ppaux::mt_to_string;
use util::ppaux::Repr;
-pub struct Lub<'f>(pub CombineFields<'f>); // least-upper-bound: common supertype
+/// "Least upper bound" (common supertype)
+pub struct Lub<'f> {
+ fields: CombineFields<'f>
+}
-impl<'f> Lub<'f> {
- pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> { let Lub(ref v) = *self; v }
+#[allow(non_snake_case)]
+pub fn Lub<'f>(cf: CombineFields<'f>) -> Lub<'f> {
+ Lub { fields: cf }
}
impl<'f> Combine for Lub<'f> {
- fn infcx<'a>(&'a self) -> &'a InferCtxt<'a> { self.get_ref().infcx }
+ fn infcx<'a>(&'a self) -> &'a InferCtxt<'a> { self.fields.infcx }
fn tag(&self) -> String { "lub".to_string() }
- fn a_is_expected(&self) -> bool { self.get_ref().a_is_expected }
- fn trace(&self) -> TypeTrace { self.get_ref().trace.clone() }
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn trace(&self) -> TypeTrace { self.fields.trace.clone() }
- fn sub<'a>(&'a self) -> Sub<'a> { Sub(self.get_ref().clone()) }
- fn lub<'a>(&'a self) -> Lub<'a> { Lub(self.get_ref().clone()) }
- fn glb<'a>(&'a self) -> Glb<'a> { Glb(self.get_ref().clone()) }
+ fn equate<'a>(&'a self) -> Equate<'a> { Equate(self.fields.clone()) }
+ fn sub<'a>(&'a self) -> Sub<'a> { Sub(self.fields.clone()) }
+ fn lub<'a>(&'a self) -> Lub<'a> { Lub(self.fields.clone()) }
+ fn glb<'a>(&'a self) -> Glb<'a> { Glb(self.fields.clone()) }
fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
- let tcx = self.get_ref().infcx.tcx;
+ let tcx = self.fields.infcx.tcx;
debug!("{}.mts({}, {})",
self.tag(),
let m = a.mutbl;
match m {
- MutImmutable => {
- self.tys(a.ty, b.ty).and_then(|t| Ok(ty::mt {ty: t, mutbl: m}) )
- }
-
- MutMutable => {
- self.get_ref().infcx.try(|| {
- eq_tys(self, a.ty, b.ty).then(|| {
- Ok(ty::mt {ty: a.ty, mutbl: m})
- })
- }).or_else(|e| Err(e))
- }
+ MutImmutable => {
+ let t = try!(self.tys(a.ty, b.ty));
+ Ok(ty::mt {ty: t, mutbl: m})
+ }
+
+ MutMutable => {
+ let t = try!(self.equate().tys(a.ty, b.ty));
+ Ok(ty::mt {ty: t, mutbl: m})
+ }
}
}
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
- a.repr(self.get_ref().infcx.tcx),
- b.repr(self.get_ref().infcx.tcx));
+ a.repr(self.fields.infcx.tcx),
+ b.repr(self.fields.infcx.tcx));
- Ok(self.get_ref().infcx.region_vars.lub_regions(Subtype(self.trace()), a, b))
+ Ok(self.fields.infcx.region_vars.lub_regions(Subtype(self.trace()), a, b))
}
fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
// Make a mark so we can examine "all bindings that were
// created as part of this type comparison".
- let mark = self.get_ref().infcx.region_vars.mark();
+ let mark = self.fields.infcx.region_vars.mark();
// Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_map) =
- self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions(
+ self.fields.infcx.replace_late_bound_regions_with_fresh_regions(
self.trace(), a);
let (b_with_fresh, _) =
- self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions(
+ self.fields.infcx.replace_late_bound_regions_with_fresh_regions(
self.trace(), b);
// Collect constraints.
- let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
- debug!("sig0 = {}", sig0.repr(self.get_ref().infcx.tcx));
+ let sig0 = try!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
+ debug!("sig0 = {}", sig0.repr(self.fields.infcx.tcx));
// Generalize the regions appearing in sig0 if possible
let new_vars =
- self.get_ref().infcx.region_vars.vars_created_since_mark(mark);
+ self.fields.infcx.region_vars.vars_created_since_mark(mark);
let sig1 =
fold_regions_in_sig(
- self.get_ref().infcx.tcx,
+ self.fields.infcx.tcx,
&sig0,
|r| generalize_region(self, mark, new_vars.as_slice(),
sig0.binder_id, &a_map, r));
return r0;
}
- let tainted = this.get_ref().infcx.region_vars.tainted(mark, r0);
+ let tainted = this.fields.infcx.region_vars.tainted(mark, r0);
// Variables created during LUB computation which are
// *related* to regions that pre-date the LUB computation
}
}
- this.get_ref().infcx.tcx.sess.span_bug(
- this.get_ref().trace.origin.span(),
+ this.fields.infcx.tcx.sess.span_bug(
+ this.fields.trace.origin.span(),
format!("region {:?} is not associated with \
any bound region from A!",
r0).as_slice())
+++ /dev/null
-// Copyright 2012 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.
-
-#![macro_escape]
-
-macro_rules! if_ok(
- ($inp: expr) => (
- match $inp {
- Ok(v) => { v }
- Err(e) => { return Err(e); }
- }
- )
-)
use middle::ty_fold::TypeFolder;
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::infer::coercion::Coerce;
-use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys};
-use middle::typeck::infer::region_inference::{RegionSnapshot};
-use middle::typeck::infer::region_inference::{RegionVarBindings};
+use middle::typeck::infer::combine::{Combine, CombineFields};
+use middle::typeck::infer::region_inference::{RegionVarBindings,
+ RegionSnapshot};
use middle::typeck::infer::resolve::{resolver};
+use middle::typeck::infer::equate::Equate;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::lub::Lub;
-use middle::typeck::infer::unify::{UnificationTable, Snapshot};
+use middle::typeck::infer::unify::{UnificationTable};
use middle::typeck::infer::error_reporting::ErrorReporting;
use std::cell::{RefCell};
use std::collections::HashMap;
use util::common::indent;
use util::ppaux::{bound_region_to_string, ty_to_string, trait_ref_to_string, Repr};
-pub mod doc;
-pub mod macros;
+pub mod coercion;
pub mod combine;
+pub mod doc;
+pub mod equate;
+pub mod error_reporting;
pub mod glb;
pub mod lattice;
pub mod lub;
pub mod region_inference;
pub mod resolve;
pub mod sub;
-pub mod unify;
-pub mod coercion;
-pub mod error_reporting;
pub mod test;
+pub mod type_variable;
+pub mod unify;
pub type Bound<T> = Option<T>;
// We instantiate UnificationTable with bounds<ty::t> because the
// types that might instantiate a general type variable have an
// order, represented by its upper and lower bounds.
- type_unification_table:
- RefCell<UnificationTable<ty::TyVid, Bounds<ty::t>>>,
+ type_variables: RefCell<type_variable::TypeVariableTable>,
// Map from integral variable to the kind of integer it represents
int_unification_table:
// Closure bound must not outlive captured free variables
FreeVariable(Span, ast::NodeId),
+ // Proc upvars must be 'static
+ ProcCapture(Span, ast::NodeId),
+
// Index into slice must be within its lifetime
IndexSlice(Span),
pub fn new_infer_ctxt<'a>(tcx: &'a ty::ctxt) -> InferCtxt<'a> {
InferCtxt {
tcx: tcx,
- type_unification_table: RefCell::new(UnificationTable::new()),
+ type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
int_unification_table: RefCell::new(UnificationTable::new()),
float_unification_table: RefCell::new(UnificationTable::new()),
region_vars: RegionVarBindings::new(tcx),
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
- let suber = cx.sub(a_is_expected, trace);
- eq_tys(&suber, a, b)
+ try!(cx.equate(a_is_expected, trace).tys(a, b));
+ Ok(())
})
}
}
pub struct CombinedSnapshot {
- type_snapshot: Snapshot<ty::TyVid>,
- int_snapshot: Snapshot<ty::IntVid>,
- float_snapshot: Snapshot<ty::FloatVid>,
+ type_snapshot: type_variable::Snapshot,
+ int_snapshot: unify::Snapshot<ty::IntVid>,
+ float_snapshot: unify::Snapshot<ty::FloatVid>,
region_vars_snapshot: RegionSnapshot,
}
trace: trace}
}
+ pub fn equate<'a>(&'a self, a_is_expected: bool, trace: TypeTrace) -> Equate<'a> {
+ Equate(self.combine_fields(a_is_expected, trace))
+ }
+
pub fn sub<'a>(&'a self, a_is_expected: bool, trace: TypeTrace) -> Sub<'a> {
Sub(self.combine_fields(a_is_expected, trace))
}
Lub(self.combine_fields(a_is_expected, trace))
}
- pub fn in_snapshot(&self) -> bool {
- self.region_vars.in_snapshot()
- }
-
fn start_snapshot(&self) -> CombinedSnapshot {
CombinedSnapshot {
- type_snapshot: self.type_unification_table.borrow_mut().snapshot(),
+ type_snapshot: self.type_variables.borrow_mut().snapshot(),
int_snapshot: self.int_unification_table.borrow_mut().snapshot(),
float_snapshot: self.float_unification_table.borrow_mut().snapshot(),
region_vars_snapshot: self.region_vars.start_snapshot(),
float_snapshot,
region_vars_snapshot } = snapshot;
- self.type_unification_table
+ self.type_variables
.borrow_mut()
- .rollback_to(self.tcx, type_snapshot);
+ .rollback_to(type_snapshot);
self.int_unification_table
.borrow_mut()
- .rollback_to(self.tcx, int_snapshot);
+ .rollback_to(int_snapshot);
self.float_unification_table
.borrow_mut()
- .rollback_to(self.tcx, float_snapshot);
+ .rollback_to(float_snapshot);
self.region_vars
.rollback_to(region_vars_snapshot);
}
float_snapshot,
region_vars_snapshot } = snapshot;
- self.type_unification_table
+ self.type_variables
.borrow_mut()
.commit(type_snapshot);
self.int_unification_table
impl<'a> InferCtxt<'a> {
pub fn next_ty_var_id(&self) -> TyVid {
- self.type_unification_table
+ self.type_variables
.borrow_mut()
- .new_key(Bounds { lb: None, ub: None })
+ .new_var()
}
pub fn next_ty_var(&self) -> ty::t {
InvokeClosure(a) => a,
DerefPointer(a) => a,
FreeVariable(a, _) => a,
+ ProcCapture(a, _) => a,
IndexSlice(a) => a,
RelateObjectBound(a) => a,
RelateProcBound(a, _, _) => a,
FreeVariable(a, b) => {
format!("FreeVariable({}, {})", a.repr(tcx), b)
}
+ ProcCapture(a, b) => {
+ format!("ProcCapture({}, {})", a.repr(tcx), b)
+ }
IndexSlice(a) => {
format!("IndexSlice({})", a.repr(tcx))
}
}
}
- pub fn in_snapshot(&self) -> bool {
+ fn in_snapshot(&self) -> bool {
self.undo_log.borrow().len() > 0
}
}
pub fn commit(&self, snapshot: RegionSnapshot) {
- debug!("RegionVarBindings: commit()");
+ debug!("RegionVarBindings: commit({})", snapshot.length);
assert!(self.undo_log.borrow().len() > snapshot.length);
assert!(*self.undo_log.borrow().get(snapshot.length) == OpenSnapshot);
}
}
+ pub fn make_eqregion(&self,
+ origin: SubregionOrigin,
+ sub: Region,
+ sup: Region) {
+ if sub != sup {
+ // Eventually, it would be nice to add direct support for
+ // equating regions.
+ self.make_subregion(origin.clone(), sub, sup);
+ self.make_subregion(origin, sup, sub);
+ }
+ }
+
pub fn make_subregion(&self,
origin: SubregionOrigin,
sub: Region,
use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid};
-use middle::ty::{type_is_bot, IntType, UintType};
+use middle::ty::{IntType, UintType};
use middle::ty;
use middle::ty_fold;
-use middle::typeck::infer::{Bounds, cyclic_ty, fixup_err, fres, InferCtxt};
-use middle::typeck::infer::{unresolved_float_ty, unresolved_int_ty};
-use middle::typeck::infer::{unresolved_ty};
+use middle::typeck::infer::{cyclic_ty, fixup_err, fres, InferCtxt};
+use middle::typeck::infer::{unresolved_int_ty,unresolved_float_ty,unresolved_ty};
use syntax::codemap::Span;
use util::common::indent;
use util::ppaux::{Repr, ty_to_string};
assert!(self.v_seen.is_empty());
match self.err {
None => {
- debug!("Resolved to {} + {} (modes={:x})",
- ty_to_string(self.infcx.tcx, rty),
+ debug!("Resolved {} to {} (modes={:x})",
+ ty_to_string(self.infcx.tcx, typ),
ty_to_string(self.infcx.tcx, rty),
self.modes);
return Ok(rty);
// tend to carry more restrictions or higher
// perf. penalties, so it pays to know more.
- let node =
- self.infcx.type_unification_table.borrow_mut().get(tcx, vid);
- let t1 = match node.value {
- Bounds { ub:_, lb:Some(t) } if !type_is_bot(t) => {
- self.resolve_type(t)
- }
- Bounds { ub:Some(t), lb:_ } | Bounds { ub:_, lb:Some(t) } => {
- self.resolve_type(t)
- }
- Bounds { ub:None, lb:None } => {
- if self.should(force_tvar) {
- self.err = Some(unresolved_ty(vid));
+ let t1 = match self.infcx.type_variables.borrow().probe(vid) {
+ Some(t) => {
+ self.resolve_type(t)
+ }
+ None => {
+ if self.should(force_tvar) {
+ self.err = Some(unresolved_ty(vid));
+ }
+ ty::mk_var(tcx, vid)
}
- ty::mk_var(tcx, vid)
- }
};
self.v_seen.pop().unwrap();
return t1;
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::{cres, CresCompare};
+use middle::typeck::infer::equate::Equate;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::InferCtxt;
-use middle::typeck::infer::lattice::CombineFieldsLatticeMethods;
use middle::typeck::infer::lub::Lub;
-use middle::typeck::infer::then;
use middle::typeck::infer::{TypeTrace, Subtype};
+use middle::typeck::infer::type_variable::{SubtypeOf, SupertypeOf};
use util::common::{indenter};
use util::ppaux::{bound_region_to_string, Repr};
use syntax::ast::{Onceness, FnStyle, MutImmutable, MutMutable};
-pub struct Sub<'f>(pub CombineFields<'f>); // "subtype", "subregion" etc
-impl<'f> Sub<'f> {
- pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> { let Sub(ref v) = *self; v }
+/// "Greatest lower bound" (common subtype)
+pub struct Sub<'f> {
+ fields: CombineFields<'f>
+}
+
+#[allow(non_snake_case)]
+pub fn Sub<'f>(cf: CombineFields<'f>) -> Sub<'f> {
+ Sub { fields: cf }
}
impl<'f> Combine for Sub<'f> {
- fn infcx<'a>(&'a self) -> &'a InferCtxt<'a> { self.get_ref().infcx }
+ fn infcx<'a>(&'a self) -> &'a InferCtxt<'a> { self.fields.infcx }
fn tag(&self) -> String { "sub".to_string() }
- fn a_is_expected(&self) -> bool { self.get_ref().a_is_expected }
- fn trace(&self) -> TypeTrace { self.get_ref().trace.clone() }
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn trace(&self) -> TypeTrace { self.fields.trace.clone() }
- fn sub<'a>(&'a self) -> Sub<'a> { Sub(self.get_ref().clone()) }
- fn lub<'a>(&'a self) -> Lub<'a> { Lub(self.get_ref().clone()) }
- fn glb<'a>(&'a self) -> Glb<'a> { Glb(self.get_ref().clone()) }
+ fn equate<'a>(&'a self) -> Equate<'a> { Equate(self.fields.clone()) }
+ fn sub<'a>(&'a self) -> Sub<'a> { Sub(self.fields.clone()) }
+ fn lub<'a>(&'a self) -> Lub<'a> { Lub(self.fields.clone()) }
+ fn glb<'a>(&'a self) -> Glb<'a> { Glb(self.fields.clone()) }
fn contratys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
- let opp = CombineFields {
- a_is_expected: !self.get_ref().a_is_expected,
- ..self.get_ref().clone()
- };
- Sub(opp).tys(b, a)
+ Sub(self.fields.switch_expected()).tys(b, a)
}
fn contraregions(&self, a: ty::Region, b: ty::Region)
- -> cres<ty::Region> {
- let opp = CombineFields {
- a_is_expected: !self.get_ref().a_is_expected,
- ..self.get_ref().clone()
- };
- Sub(opp).regions(b, a)
- }
+ -> cres<ty::Region> {
+ let opp = CombineFields {
+ a_is_expected: !self.fields.a_is_expected,
+ ..self.fields.clone()
+ };
+ Sub(opp).regions(b, a)
+ }
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
debug!("{}.regions({}, {})",
self.tag(),
- a.repr(self.get_ref().infcx.tcx),
- b.repr(self.get_ref().infcx.tcx));
- self.get_ref().infcx.region_vars.make_subregion(Subtype(self.trace()), a, b);
+ a.repr(self.fields.infcx.tcx),
+ b.repr(self.fields.infcx.tcx));
+ self.fields.infcx.region_vars.make_subregion(Subtype(self.trace()), a, b);
Ok(a)
}
fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
debug!("mts({} <: {})",
- a.repr(self.get_ref().infcx.tcx),
- b.repr(self.get_ref().infcx.tcx));
+ a.repr(self.fields.infcx.tcx),
+ b.repr(self.fields.infcx.tcx));
if a.mutbl != b.mutbl {
return Err(ty::terr_mutability);
}
match b.mutbl {
- MutMutable => {
- // If supertype is mut, subtype must match exactly
- // (i.e., invariant if mut):
- eq_tys(self, a.ty, b.ty).then(|| Ok(*a))
- }
- MutImmutable => {
- // Otherwise we can be covariant:
- self.tys(a.ty, b.ty).and_then(|_t| Ok(*a) )
- }
+ MutMutable => {
+ // If supertype is mut, subtype must match exactly
+ // (i.e., invariant if mut):
+ try!(self.equate().tys(a.ty, b.ty));
+ }
+ MutImmutable => {
+ // Otherwise we can be covariant:
+ try!(self.tys(a.ty, b.ty));
+ }
}
+
+ Ok(*a) // return is meaningless in sub, just return *a
}
fn fn_styles(&self, a: FnStyle, b: FnStyle) -> cres<FnStyle> {
fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
debug!("{}.tys({}, {})", self.tag(),
- a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
+ a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
if a == b { return Ok(a); }
- let _indenter = indenter();
+
+ let infcx = self.fields.infcx;
+ let a = infcx.type_variables.borrow().replace_if_possible(a);
+ let b = infcx.type_variables.borrow().replace_if_possible(b);
match (&ty::get(a).sty, &ty::get(b).sty) {
(&ty::ty_bot, _) => {
Ok(a)
}
(&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
- if_ok!(self.get_ref().var_sub_var(a_id, b_id));
+ infcx.type_variables
+ .borrow_mut()
+ .relate_vars(a_id, SubtypeOf, b_id);
Ok(a)
}
// The vec/str check here and below is so that we don't unify
Err(ty::terr_sorts(expected_found(self, a, b)))
}
(&ty::ty_infer(TyVar(a_id)), _) => {
- if_ok!(self.get_ref().var_sub_t(a_id, b));
+ try!(self.fields
+ .switch_expected()
+ .instantiate(b, SupertypeOf, a_id));
Ok(a)
}
Err(ty::terr_sorts(expected_found(self, a, b)))
}
(_, &ty::ty_infer(TyVar(b_id))) => {
- if_ok!(self.get_ref().t_sub_var(a, b_id));
+ try!(self.fields.instantiate(a, SubtypeOf, b_id));
Ok(a)
}
fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
debug!("fn_sigs(a={}, b={})",
- a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
+ a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
let _indenter = indenter();
// Rather than checking the subtype relationship between `a` and `b`
// Make a mark so we can examine "all bindings that were
// created as part of this type comparison".
- let mark = self.get_ref().infcx.region_vars.mark();
+ let mark = self.fields.infcx.region_vars.mark();
// First, we instantiate each bound region in the subtype with a fresh
// region variable.
let (a_sig, _) =
- self.get_ref().infcx.replace_late_bound_regions_with_fresh_regions(
+ self.fields.infcx.replace_late_bound_regions_with_fresh_regions(
self.trace(), a);
// Second, we instantiate each bound region in the supertype with a
// fresh concrete region.
let (skol_map, b_sig) = {
- replace_late_bound_regions_in_fn_sig(self.get_ref().infcx.tcx, b, |br| {
- let skol = self.get_ref().infcx.region_vars.new_skolemized(br);
+ replace_late_bound_regions_in_fn_sig(self.fields.infcx.tcx, b, |br| {
+ let skol = self.fields.infcx.region_vars.new_skolemized(br);
debug!("Bound region {} skolemized to {:?}",
- bound_region_to_string(self.get_ref().infcx.tcx, "", false, br),
+ bound_region_to_string(self.fields.infcx.tcx, "", false, br),
skol);
skol
})
};
- debug!("a_sig={}", a_sig.repr(self.get_ref().infcx.tcx));
- debug!("b_sig={}", b_sig.repr(self.get_ref().infcx.tcx));
+ debug!("a_sig={}", a_sig.repr(self.fields.infcx.tcx));
+ debug!("b_sig={}", b_sig.repr(self.fields.infcx.tcx));
// Compare types now that bound regions have been replaced.
- let sig = if_ok!(super_fn_sigs(self, &a_sig, &b_sig));
+ let sig = try!(super_fn_sigs(self, &a_sig, &b_sig));
// Presuming type comparison succeeds, we need to check
// that the skolemized regions do not "leak".
let new_vars =
- self.get_ref().infcx.region_vars.vars_created_since_mark(mark);
+ self.fields.infcx.region_vars.vars_created_since_mark(mark);
for (&skol_br, &skol) in skol_map.iter() {
- let tainted = self.get_ref().infcx.region_vars.tainted(mark, skol);
+ let tainted = self.fields.infcx.region_vars.tainted(mark, skol);
for tainted_region in tainted.iter() {
// Each skolemized should only be relatable to itself
// or new variables:
if self.a_is_expected() {
debug!("Not as polymorphic!");
return Err(ty::terr_regions_insufficiently_polymorphic(
- skol_br, *tainted_region));
+ skol_br, *tainted_region));
} else {
debug!("Overly polymorphic!");
return Err(ty::terr_regions_overly_polymorphic(
- skol_br, *tainted_region));
+ skol_br, *tainted_region));
}
}
}
return Ok(sig);
}
-
}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use middle::ty;
+use std::mem;
+use util::snapshot_vec as sv;
+
+pub struct TypeVariableTable {
+ values: sv::SnapshotVec<TypeVariableData,UndoEntry,Delegate>,
+}
+
+struct TypeVariableData {
+ value: TypeVariableValue
+}
+
+enum TypeVariableValue {
+ Known(ty::t),
+ Bounded(Vec<Relation>),
+}
+
+pub struct Snapshot {
+ snapshot: sv::Snapshot
+}
+
+enum UndoEntry {
+ // The type of the var was specified.
+ SpecifyVar(ty::TyVid, Vec<Relation>),
+ Relate(ty::TyVid, ty::TyVid),
+}
+
+struct Delegate;
+
+type Relation = (RelationDir, ty::TyVid);
+
+#[deriving(PartialEq,Show)]
+pub enum RelationDir {
+ SubtypeOf, SupertypeOf, EqTo
+}
+
+impl RelationDir {
+ fn opposite(self) -> RelationDir {
+ match self {
+ SubtypeOf => SupertypeOf,
+ SupertypeOf => SubtypeOf,
+ EqTo => EqTo
+ }
+ }
+}
+
+impl TypeVariableTable {
+ pub fn new() -> TypeVariableTable {
+ TypeVariableTable { values: sv::SnapshotVec::new(Delegate) }
+ }
+
+ fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec<Relation> {
+ relations(self.values.get_mut(a.index))
+ }
+
+ pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) {
+ /*!
+ * Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`.
+ *
+ * Precondition: neither `a` nor `b` are known.
+ */
+
+ if a != b {
+ self.relations(a).push((dir, b));
+ self.relations(b).push((dir.opposite(), a));
+ self.values.record(Relate(a, b));
+ }
+ }
+
+ pub fn instantiate_and_push(
+ &mut self,
+ vid: ty::TyVid,
+ ty: ty::t,
+ stack: &mut Vec<(ty::t, RelationDir, ty::TyVid)>)
+ {
+ /*!
+ * Instantiates `vid` with the type `ty` and then pushes an
+ * entry onto `stack` for each of the relations of `vid` to
+ * other variables. The relations will have the form `(ty,
+ * dir, vid1)` where `vid1` is some other variable id.
+ */
+
+ let old_value = {
+ let value_ptr = &mut self.values.get_mut(vid.index).value;
+ mem::replace(value_ptr, Known(ty))
+ };
+
+ let relations = match old_value {
+ Bounded(b) => b,
+ Known(_) => fail!("Asked to instantiate variable that is \
+ already instantiated")
+ };
+
+ for &(dir, vid) in relations.iter() {
+ stack.push((ty, dir, vid));
+ }
+
+ self.values.record(SpecifyVar(vid, relations));
+ }
+
+ pub fn new_var(&mut self) -> ty::TyVid {
+ let index =
+ self.values.push(
+ TypeVariableData { value: Bounded(Vec::new()) });
+ ty::TyVid { index: index }
+ }
+
+ pub fn probe(&self, vid: ty::TyVid) -> Option<ty::t> {
+ match self.values.get(vid.index).value {
+ Bounded(..) => None,
+ Known(t) => Some(t)
+ }
+ }
+
+ pub fn replace_if_possible(&self, t: ty::t) -> ty::t {
+ match ty::get(t).sty {
+ ty::ty_infer(ty::TyVar(v)) => {
+ match self.probe(v) {
+ None => t,
+ Some(u) => u
+ }
+ }
+ _ => t,
+ }
+ }
+
+ pub fn snapshot(&mut self) -> Snapshot {
+ Snapshot { snapshot: self.values.start_snapshot() }
+ }
+
+ pub fn rollback_to(&mut self, s: Snapshot) {
+ self.values.rollback_to(s.snapshot);
+ }
+
+ pub fn commit(&mut self, s: Snapshot) {
+ self.values.commit(s.snapshot);
+ }
+}
+
+impl sv::SnapshotVecDelegate<TypeVariableData,UndoEntry> for Delegate {
+ fn reverse(&mut self,
+ values: &mut Vec<TypeVariableData>,
+ action: UndoEntry) {
+ match action {
+ SpecifyVar(vid, relations) => {
+ values.get_mut(vid.index).value = Bounded(relations);
+ }
+
+ Relate(a, b) => {
+ relations(values.get_mut(a.index)).pop();
+ relations(values.get_mut(b.index)).pop();
+ }
+ }
+ }
+}
+
+fn relations<'a>(v: &'a mut TypeVariableData) -> &'a mut Vec<Relation> {
+ match v.value {
+ Known(_) => fail!("var_sub_var: variable is known"),
+ Bounded(ref mut relations) => relations
+ }
+}
+
use middle::ty::{expected_found, IntVarValue};
use middle::ty;
-use middle::typeck::infer::{Bounds, uok, ures};
+use middle::typeck::infer::{uok, ures};
use middle::typeck::infer::InferCtxt;
use std::cell::RefCell;
use std::fmt::Show;
-use std::mem;
use syntax::ast;
use util::ppaux::Repr;
+use util::snapshot_vec as sv;
/**
* This trait is implemented by any type that can serve as a type
* variable. We call such variables *unification keys*. For example,
- * this trait is implemented by `TyVid`, which represents normal
- * type variables, and `IntVid`, which represents integral variables.
+ * this trait is implemented by `IntVid`, which represents integral
+ * variables.
*
- * Each key type has an associated value type `V`. For example,
- * for `TyVid`, this is `Bounds<ty::t>`, representing a pair of
- * upper- and lower-bound types.
+ * Each key type has an associated value type `V`. For example, for
+ * `IntVid`, this is `Option<IntVarValue>`, representing some
+ * (possibly not yet known) sort of integer.
*
* Implementations of this trait are at the end of this file.
*/
}
/**
- * Trait for valid types that a type variable can be set to. Note
- * that this is typically not the end type that the value will
- * take on, but rather some wrapper: for example, for normal type
- * variables, the associated type is not `ty::t` but rather
- * `Bounds<ty::t>`.
+ * Trait for valid types that a type variable can be set to. Note that
+ * this is typically not the end type that the value will take on, but
+ * rather an `Option` wrapper (where `None` represents a variable
+ * whose value is not yet set).
*
* Implementations of this trait are at the end of this file.
*/
/**
* Indicates the current value of each key.
*/
- values: Vec<VarValue<K,V>>,
- /**
- * When a snapshot is active, logs each change made to the table
- * so that they can be unrolled.
- */
- undo_log: Vec<UndoLog<K,V>>,
+ values: sv::SnapshotVec<VarValue<K,V>,(),Delegate>,
}
/**
* made during the snapshot may either be *committed* or *rolled back*.
*/
pub struct Snapshot<K> {
- // Ensure that this snapshot is keyed to the table type.
- marker1: marker::CovariantType<K>,
-
- // Snapshots are tokens that should be created/consumed linearly.
- marker2: marker::NoCopy,
-
- // Length of the undo log at the time the snapshot was taken.
- length: uint,
-}
-
-#[deriving(PartialEq)]
-enum UndoLog<K,V> {
- /// Indicates where a snapshot started.
- OpenSnapshot,
-
- /// Indicates a snapshot that has been committed.
- CommittedSnapshot,
-
- /// New variable with given index was created.
- NewVar(uint),
-
- /// Variable with given index was changed *from* the given value.
- SetVar(uint, VarValue<K,V>),
+ // Link snapshot to the key type `K` of the table.
+ marker: marker::CovariantType<K>,
+ snapshot: sv::Snapshot,
}
/**
pub rank: uint,
}
+pub struct Delegate;
+
// We can't use V:LatticeValue, much as I would like to,
-// because frequently the pattern is that V=Bounds<U> for some
+// because frequently the pattern is that V=Option<U> for some
// other type parameter U, and we have no way to say
-// Bounds<U>:
+// Option<U>:LatticeValue.
impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
pub fn new() -> UnificationTable<K,V> {
UnificationTable {
- values: Vec::new(),
- undo_log: Vec::new()
+ values: sv::SnapshotVec::new(Delegate),
}
}
- pub fn in_snapshot(&self) -> bool {
- /*! True if a snapshot has been started. */
-
- self.undo_log.len() > 0
- }
-
/**
* Starts a new snapshot. Each snapshot must be either
* rolled back or committed in a "LIFO" (stack) order.
*/
pub fn snapshot(&mut self) -> Snapshot<K> {
- let length = self.undo_log.len();
- debug!("{}: snapshot at length {}",
- UnifyKey::tag(None::<K>),
- length);
- self.undo_log.push(OpenSnapshot);
- Snapshot { length: length,
- marker1: marker::CovariantType,
- marker2: marker::NoCopy }
- }
-
- fn assert_open_snapshot(&self, snapshot: &Snapshot<K>) {
- // Or else there was a failure to follow a stack discipline:
- assert!(self.undo_log.len() > snapshot.length);
-
- // Invariant established by start_snapshot():
- assert!(*self.undo_log.get(snapshot.length) == OpenSnapshot);
+ Snapshot { marker: marker::CovariantType::<K>,
+ snapshot: self.values.start_snapshot() }
}
/**
* Reverses all changes since the last snapshot. Also
* removes any keys that have been created since then.
*/
- pub fn rollback_to(&mut self, tcx: &ty::ctxt, snapshot: Snapshot<K>) {
- debug!("{}: rollback_to({})",
- UnifyKey::tag(None::<K>),
- snapshot.length);
-
- self.assert_open_snapshot(&snapshot);
-
- while self.undo_log.len() > snapshot.length + 1 {
- match self.undo_log.pop().unwrap() {
- OpenSnapshot => {
- // This indicates a failure to obey the stack discipline.
- tcx.sess.bug("Cannot rollback an uncommitted snapshot");
- }
-
- CommittedSnapshot => {
- // This occurs when there are nested snapshots and
- // the inner is committed but outer is rolled back.
- }
-
- NewVar(i) => {
- assert!(self.values.len() == i);
- self.values.pop();
- }
-
- SetVar(i, v) => {
- *self.values.get_mut(i) = v;
- }
- }
- }
-
- let v = self.undo_log.pop().unwrap();
- assert!(v == OpenSnapshot);
- assert!(self.undo_log.len() == snapshot.length);
+ pub fn rollback_to(&mut self, snapshot: Snapshot<K>) {
+ debug!("{}: rollback_to()", UnifyKey::tag(None::<K>));
+ self.values.rollback_to(snapshot.snapshot);
}
/**
* can still be undone if there is a snapshot further out.
*/
pub fn commit(&mut self, snapshot: Snapshot<K>) {
- debug!("{}: commit({})",
- UnifyKey::tag(None::<K>),
- snapshot.length);
-
- self.assert_open_snapshot(&snapshot);
-
- if snapshot.length == 0 {
- // The root snapshot.
- self.undo_log.truncate(0);
- } else {
- *self.undo_log.get_mut(snapshot.length) = CommittedSnapshot;
- }
+ debug!("{}: commit()", UnifyKey::tag(None::<K>));
+ self.values.commit(snapshot.snapshot);
}
pub fn new_key(&mut self, value: V) -> K {
- let index = self.values.len();
-
- if self.in_snapshot() {
- self.undo_log.push(NewVar(index));
- }
-
- self.values.push(Root(value, 0));
+ let index = self.values.push(Root(value, 0));
let k = UnifyKey::from_index(index);
debug!("{}: created new key: {}",
UnifyKey::tag(None::<K>),
k
}
- fn swap_value(&mut self,
- index: uint,
- new_value: VarValue<K,V>)
- -> VarValue<K,V>
- {
- /*!
- * Primitive operation to swap a value in the var array.
- * Caller should update the undo log if we are in a snapshot.
- */
-
- let loc = self.values.get_mut(index);
- mem::replace(loc, new_value)
- }
-
pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node<K,V> {
/*!
* Find the root node for `vid`. This uses the standard
let node: Node<K,V> = self.get(tcx, redirect.clone());
if node.key != redirect {
// Path compression
- let old_value =
- self.swap_value(index, Redirect(node.key.clone()));
-
- // If we are in a snapshot, record this compression,
- // because it's possible that the unification which
- // caused it will be rolled back later.
- if self.in_snapshot() {
- self.undo_log.push(SetVar(index, old_value));
- }
+ self.values.set(index, Redirect(node.key.clone()));
}
node
}
*/
assert!(self.is_root(&key));
- assert!(self.in_snapshot());
debug!("Updating variable {} to {}",
key.repr(tcx),
new_value.repr(tcx));
- let index = key.index();
- let old_value = self.swap_value(index, new_value);
- self.undo_log.push(SetVar(index, old_value));
+ self.values.set(key.index(), new_value);
}
pub fn unify(&mut self,
}
}
+impl<K,V> sv::SnapshotVecDelegate<VarValue<K,V>,()> for Delegate {
+ fn reverse(&mut self, _: &mut Vec<VarValue<K,V>>, _: ()) {
+ fail!("Nothing to reverse");
+ }
+}
+
///////////////////////////////////////////////////////////////////////////
// Code to handle simple keys like ints, floats---anything that
// doesn't have a subtyping relationship we need to worry about.
pub fn err<V:SimplyUnifiable>(a_is_expected: bool,
a_t: V,
- b_t: V) -> ures {
+ b_t: V)
+ -> ures {
if a_is_expected {
Err(SimplyUnifiable::to_type_err(
ty::expected_found {expected: a_t, found: b_t}))
///////////////////////////////////////////////////////////////////////////
-// General type keys
-
-impl UnifyKey<Bounds<ty::t>> for ty::TyVid {
- fn index(&self) -> uint { self.index }
-
- fn from_index(i: uint) -> ty::TyVid { ty::TyVid { index: i } }
-
- fn unification_table<'v>(infcx: &'v InferCtxt)
- -> &'v RefCell<UnificationTable<ty::TyVid, Bounds<ty::t>>>
- {
- return &infcx.type_unification_table;
- }
-
- fn tag(_: Option<ty::TyVid>) -> &'static str {
- "TyVid"
- }
-}
-
-impl UnifyValue for Bounds<ty::t> { }
-
// Integral type keys
impl UnifyKey<Option<IntVarValue>> for ty::IntVid {
//! Used by plugin crates to tell `rustc` about the plugins they provide.
-use lint::LintPassObject;
+use lint::{LintPassObject, LintId, Lint};
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
use syntax::ext::base::{IdentTT, LetSyntaxTT, ItemDecorator, ItemModifier, BasicMacroExpander};
use syntax::parse::token;
use syntax::ast;
+use std::collections::HashMap;
+
/// Structure used to register plugins.
///
/// A plugin registrar function takes an `&mut Registry` and should call
#[doc(hidden)]
pub lint_passes: Vec<LintPassObject>,
+
+ #[doc(hidden)]
+ pub lint_groups: HashMap<&'static str, Vec<LintId>>,
}
impl Registry {
krate_span: krate.span,
syntax_exts: vec!(),
lint_passes: vec!(),
+ lint_groups: HashMap::new(),
}
}
pub fn register_lint_pass(&mut self, lint_pass: LintPassObject) {
self.lint_passes.push(lint_pass);
}
+
+ /// Register a lint group.
+ pub fn register_lint_group(&mut self, name: &'static str, to: Vec<&'static Lint>) {
+ self.lint_groups.insert(name, to.move_iter().map(|x| LintId::of(x)).collect());
+ }
}
//! An efficient hash map for node IDs
+#![allow(non_snake_case)]
+
use std::collections::{HashMap, HashSet};
use std::hash::{Hasher, Hash, Writer};
use syntax::ast;
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+ * A utility class for implementing "snapshottable" things; a
+ * snapshottable data structure permits you to take a snapshot (via
+ * `start_snapshot`) and then, after making some changes, elect either
+ * to rollback to the start of the snapshot or commit those changes.
+ *
+ * This vector is intended to be used as part of an abstraction, not
+ * serve as a complete abstraction on its own. As such, while it will
+ * roll back most changes on its own, it also supports a `get_mut`
+ * operation that gives you an abitrary mutable pointer into the
+ * vector. To ensure that any changes you make this with this pointer
+ * are rolled back, you must invoke `record` to record any changes you
+ * make and also supplying a delegate capable of reversing those
+ * changes.
+ */
+
+use std::kinds::marker;
+use std::mem;
+
+#[deriving(PartialEq)]
+enum UndoLog<T,U> {
+ /// Indicates where a snapshot started.
+ OpenSnapshot,
+
+ /// Indicates a snapshot that has been committed.
+ CommittedSnapshot,
+
+ /// New variable with given index was created.
+ NewElem(uint),
+
+ /// Variable with given index was changed *from* the given value.
+ SetElem(uint, T),
+
+ /// Extensible set of actions
+ Other(U)
+}
+
+pub struct SnapshotVec<T,U,D> {
+ values: Vec<T>,
+ undo_log: Vec<UndoLog<T,U>>,
+ delegate: D
+}
+
+pub struct Snapshot {
+ // Snapshots are tokens that should be created/consumed linearly.
+ marker: marker::NoCopy,
+
+ // Length of the undo log at the time the snapshot was taken.
+ length: uint,
+}
+
+pub trait SnapshotVecDelegate<T,U> {
+ fn reverse(&mut self, values: &mut Vec<T>, action: U);
+}
+
+impl<T,U,D:SnapshotVecDelegate<T,U>> SnapshotVec<T,U,D> {
+ pub fn new(delegate: D) -> SnapshotVec<T,U,D> {
+ SnapshotVec {
+ values: Vec::new(),
+ undo_log: Vec::new(),
+ delegate: delegate
+ }
+ }
+
+ fn in_snapshot(&self) -> bool {
+ !self.undo_log.is_empty()
+ }
+
+ pub fn record(&mut self, action: U) {
+ if self.in_snapshot() {
+ self.undo_log.push(Other(action));
+ }
+ }
+
+ pub fn push(&mut self, elem: T) -> uint {
+ let len = self.values.len();
+ self.values.push(elem);
+
+ if self.in_snapshot() {
+ self.undo_log.push(NewElem(len));
+ }
+
+ len
+ }
+
+ pub fn get<'a>(&'a self, index: uint) -> &'a T {
+ self.values.get(index)
+ }
+
+ pub fn get_mut<'a>(&'a mut self, index: uint) -> &'a mut T {
+ /*!
+ * Returns a mutable pointer into the vec; whatever changes
+ * you make here cannot be undone automatically, so you should
+ * be sure call `record()` with some sort of suitable undo
+ * action.
+ */
+
+ self.values.get_mut(index)
+ }
+
+ pub fn set(&mut self, index: uint, new_elem: T) {
+ /*!
+ * Updates the element at the given index. The old value will
+ * saved (and perhaps restored) if a snapshot is active.
+ */
+
+ let old_elem = mem::replace(self.values.get_mut(index), new_elem);
+ if self.in_snapshot() {
+ self.undo_log.push(SetElem(index, old_elem));
+ }
+ }
+
+ pub fn start_snapshot(&mut self) -> Snapshot {
+ let length = self.undo_log.len();
+ self.undo_log.push(OpenSnapshot);
+ Snapshot { length: length,
+ marker: marker::NoCopy }
+ }
+
+ fn assert_open_snapshot(&self, snapshot: &Snapshot) {
+ // Or else there was a failure to follow a stack discipline:
+ assert!(self.undo_log.len() > snapshot.length);
+
+ // Invariant established by start_snapshot():
+ assert!(
+ match *self.undo_log.get(snapshot.length) {
+ OpenSnapshot => true,
+ _ => false
+ });
+ }
+
+ pub fn rollback_to(&mut self, snapshot: Snapshot) {
+ debug!("rollback_to({})", snapshot.length);
+
+ self.assert_open_snapshot(&snapshot);
+
+ while self.undo_log.len() > snapshot.length + 1 {
+ match self.undo_log.pop().unwrap() {
+ OpenSnapshot => {
+ // This indicates a failure to obey the stack discipline.
+ fail!("Cannot rollback an uncommited snapshot");
+ }
+
+ CommittedSnapshot => {
+ // This occurs when there are nested snapshots and
+ // the inner is commited but outer is rolled back.
+ }
+
+ NewElem(i) => {
+ self.values.pop();
+ assert!(self.values.len() == i);
+ }
+
+ SetElem(i, v) => {
+ *self.values.get_mut(i) = v;
+ }
+
+ Other(u) => {
+ self.delegate.reverse(&mut self.values, u);
+ }
+ }
+ }
+
+ let v = self.undo_log.pop().unwrap();
+ assert!(match v { OpenSnapshot => true, _ => false });
+ assert!(self.undo_log.len() == snapshot.length);
+ }
+
+ /**
+ * Commits all changes since the last snapshot. Of course, they
+ * can still be undone if there is a snapshot further out.
+ */
+ pub fn commit(&mut self, snapshot: Snapshot) {
+ debug!("commit({})", snapshot.length);
+
+ self.assert_open_snapshot(&snapshot);
+
+ if snapshot.length == 0 {
+ // The root snapshot.
+ self.undo_log.truncate(0);
+ } else {
+ *self.undo_log.get_mut(snapshot.length) = CommittedSnapshot;
+ }
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(non_uppercase_pattern_statics)]
+#![allow(non_uppercase_statics)]
#![allow(non_camel_case_types)]
-#![allow(non_snake_case_functions)]
+#![allow(non_snake_case)]
#![allow(dead_code)]
#![crate_name = "rustc_llvm"]
FlagObjcClassComplete = 1 << 9,
FlagObjectPointer = 1 << 10,
FlagVector = 1 << 11,
- FlagStaticMember = 1 << 12
+ FlagStaticMember = 1 << 12,
+ FlagIndirectVariable = 1 << 13,
+ FlagLValueReference = 1 << 14,
+ FlagRValueReference = 1 << 15
}
}
static LOCKFILE_EXCLUSIVE_LOCK: libc::DWORD = 0x00000002;
- #[allow(non_snake_case_functions)]
+ #[allow(non_snake_case)]
extern "system" {
fn LockFileEx(hFile: libc::HANDLE,
dwFlags: libc::DWORD,
// Index this method for searching later on
match item.name {
Some(ref s) => {
- let parent = match item.inner {
+ let (parent, is_method) = match item.inner {
clean::TyMethodItem(..) |
clean::StructFieldItem(..) |
clean::VariantItem(..) => {
- (Some(*self.parent_stack.last().unwrap()),
- Some(self.stack.slice_to(self.stack.len() - 1)))
+ ((Some(*self.parent_stack.last().unwrap()),
+ Some(self.stack.slice_to(self.stack.len() - 1))),
+ false)
}
clean::MethodItem(..) => {
if self.parent_stack.len() == 0 {
- (None, None)
+ ((None, None), false)
} else {
let last = self.parent_stack.last().unwrap();
let did = *last;
Some(..) => Some(self.stack.as_slice()),
None => None
};
- (Some(*last), path)
+ ((Some(*last), path), true)
}
}
- _ => (None, Some(self.stack.as_slice()))
+ _ => ((None, Some(self.stack.as_slice())), false)
};
let hidden_field = match item.inner {
clean::StructFieldItem(clean::HiddenStructField) => true,
_ => false
};
+
match parent {
- (parent, Some(path)) if !self.privmod && !hidden_field => {
+ (parent, Some(path)) if is_method || (!self.privmod && !hidden_field) => {
self.search_index.push(IndexItem {
ty: shortty(&item),
name: s.to_string(),
parent: parent,
});
}
- (Some(parent), None) if !self.privmod => {
+ (Some(parent), None) if is_method || (!self.privmod && !hidden_field)=> {
if ast_util::is_local(parent) {
// We have a parent, but we don't know where they're
// defined yet. Wait for later to index this item.
data: UnsafeCell<T>,
}
-/// stage0 only
-#[cfg(stage0)]
-pub struct ExclusiveGuard<'a, T> {
- // FIXME #12808: strange name to try to avoid interfering with
- // field accesses of the contained type via Deref
- _data: &'a mut T,
- _guard: mutex::LockGuard<'a>,
-}
-
/// An RAII guard returned via `lock`
-#[cfg(not(stage0))]
pub struct ExclusiveGuard<'a, T:'a> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
#![feature(linkage, lang_items, unsafe_destructor, default_type_params)]
#![feature(import_shadowing)]
-#![feature(issue_5723_bootstrap)]
#![no_std]
#![experimental]
-// NOTE(stage0, pcwalton): Remove after snapshot.
-#![allow(unknown_features)]
-
#[phase(plugin, link)] extern crate core;
extern crate alloc;
extern crate libc;
//! Unwind library interface
#![allow(non_camel_case_types)]
-#![allow(non_snake_case_functions)]
+#![allow(non_snake_case)]
#![allow(dead_code)] // these are just bindings
use libc;
///
/// The task-local data can be accessed through this value, and when this
/// structure is dropped it will return the borrow on the data.
-#[cfg(not(stage0))]
pub struct Ref<T:'static> {
// FIXME #12808: strange names to try to avoid interfering with
// field accesses of the contained type via Deref
_marker: marker::NoSend
}
-/// stage0 only
-#[cfg(stage0)]
-pub struct Ref<T> {
- // FIXME #12808: strange names to try to avoid interfering with
- // field accesses of the contained type via Deref
- _inner: &'static TLDValueBox<T>,
- _marker: marker::NoSend
-}
-
fn key_to_key_value<T: 'static>(key: Key<T>) -> uint {
key as *const _ as uint
}
// Do nothing.
None
}
- (0, Some(newValue)) => {
+ (0, Some(new_value)) => {
// The current value is uninitialized and we're storing a new value.
unsafe {
- ptr::write(&mut (*value_box).value, newValue);
+ ptr::write(&mut (*value_box).value, new_value);
*(*value_box).refcount.get() = 1;
None
}
Some(ret)
}
}
- (1, Some(newValue)) => {
+ (1, Some(new_value)) => {
// We have an initialized value and we're replacing it.
let value_ref = unsafe { &mut (*value_box).value };
- let ret = mem::replace(value_ref, newValue);
+ let ret = mem::replace(value_ref, new_value);
// Refcount is already 1, leave it as that.
Some(ret)
}
libc::CloseHandle(block);
}
- #[allow(non_snake_case_functions)]
+ #[allow(non_snake_case)]
extern "system" {
fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
bManualReset: BOOL,
SwitchToThread();
}
- #[allow(non_snake_case_functions)]
+ #[allow(non_snake_case)]
extern "system" {
fn CreateThread(lpThreadAttributes: LPSECURITY_ATTRIBUTES,
dwStackSize: SIZE_T,
}
#[cfg(windows)]
-#[allow(non_snake_case_functions)]
+#[allow(non_snake_case)]
extern "system" {
fn TlsAlloc() -> DWORD;
fn TlsFree(dwTlsIndex: DWORD) -> BOOL;
inner: Arc<UnsafeCell<Inner<T>>>,
}
-#[cfg(stage0)]
-pub struct Guard<'a, T> {
- access: &'a mut Access<T>,
- missile: Option<HomingMissile>,
-}
-
-#[cfg(not(stage0))]
pub struct Guard<'a, T:'static> {
access: &'a mut Access<T>,
missile: Option<HomingMissile>,
pub access: access::Access<T>,
}
-#[cfg(stage0)]
-pub struct Guard<'a, T> {
- state: &'a mut TimeoutState,
- pub access: access::Guard<'a, T>,
- pub can_timeout: bool,
-}
-
-#[cfg(not(stage0))]
pub struct Guard<'a, T:'static> {
state: &'a mut TimeoutState,
pub access: access::Guard<'a, T>,
> ToJson for ( $( $tyvar ),* , ) {
#[inline]
- #[allow(uppercase_variables)]
+ #[allow(non_snake_case)]
fn to_json(&self) -> Json {
match *self {
($(ref $tyvar),*,) => List(vec![$($tyvar.to_json()),*])
html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase)]
-#![feature(issue_5723_bootstrap)]
// test harness access
#[cfg(test)]
() => ();
( $($name:ident,)+ ) => (
impl<E, D:Decoder<E>,$($name:Decodable<D, E>),*> Decodable<D,E> for ($($name,)*) {
- #[allow(uppercase_variables)]
+ #[allow(non_snake_case)]
fn decode(d: &mut D) -> Result<($($name,)*), E> {
d.read_tuple(|d, amt| {
let mut i = 0;
}
}
impl<E, S:Encoder<E>,$($name:Encodable<S, E>),*> Encodable<S, E> for ($($name,)*) {
- #[allow(uppercase_variables)]
+ #[allow(non_snake_case)]
fn encode(&self, s: &mut S) -> Result<(), E> {
let ($(ref $name,)*) = *self;
let mut n = 0;
assert_eq!(size_of::<SafeHash>(), size_of::<u64>())
}
- /// Note: stage0-specific version that lacks bound.
- #[cfg(stage0)]
- pub struct Entries<'a, K, V> {
- table: &'a RawTable<K, V>,
- idx: uint,
- elems_seen: uint,
- }
-
/// Iterator over shared references to entries in a table.
- #[cfg(not(stage0))]
pub struct Entries<'a, K:'a, V:'a> {
table: &'a RawTable<K, V>,
idx: uint,
elems_seen: uint,
}
- /// Note: stage0-specific version that lacks bound.
- #[cfg(stage0)]
- pub struct MutEntries<'a, K, V> {
- table: &'a mut RawTable<K, V>,
- idx: uint,
- elems_seen: uint,
- }
-
/// Iterator over mutable references to entries in a table.
- #[cfg(not(stage0))]
pub struct MutEntries<'a, K:'a, V:'a> {
table: &'a mut RawTable<K, V>,
idx: uint,
FreeLibrary(handle as *mut libc::c_void); ()
}
- #[allow(non_snake_case_functions)]
+ #[allow(non_snake_case)]
extern "system" {
fn SetLastError(error: libc::size_t);
fn LoadLibraryW(name: *const libc::c_void) -> *mut libc::c_void;
///
/// Any error other than `EndOfFile` that is produced by the underlying Reader
/// is returned by the iterator and should be handled by the caller.
-#[cfg(stage0)]
-pub struct Bytes<'r, T> {
- reader: &'r mut T,
-}
-
-/// An iterator that reads a single byte on each iteration,
-/// until `.read_byte()` returns `EndOfFile`.
-///
-/// # Notes about the Iteration Protocol
-///
-/// The `Bytes` may yield `None` and thus terminate
-/// an iteration, but continue to yield elements if iteration
-/// is attempted again.
-///
-/// # Error
-///
-/// Any error other than `EndOfFile` that is produced by the underlying Reader
-/// is returned by the iterator and should be handled by the caller.
-#[cfg(not(stage0))]
pub struct Bytes<'r, T:'r> {
reader: &'r mut T,
}
})
}
-/// Note: stage0-specific version that lacks bound.
-#[cfg(stage0)]
-pub struct RefReader<'a, R> {
- /// The underlying reader which this is referencing
- inner: &'a mut R
-}
-
/// A `RefReader` is a struct implementing `Reader` which contains a reference
/// to another reader. This is often useful when composing streams.
///
///
/// # }
/// ```
-#[cfg(not(stage0))]
pub struct RefReader<'a, R:'a> {
/// The underlying reader which this is referencing
inner: &'a mut R
///
/// This function will return any I/O error reported while formatting.
fn write_fmt(&mut self, fmt: &fmt::Arguments) -> IoResult<()> {
- // Note: stage0-specific version that lacks bound.
- #[cfg(stage0)]
- struct Adaptor<'a, T> {
- inner: &'a mut T,
- error: IoResult<()>,
- }
-
// Create a shim which translates a Writer to a FormatWriter and saves
// off I/O errors. instead of discarding them
- #[cfg(not(stage0))]
struct Adaptor<'a, T:'a> {
inner: &'a mut T,
error: IoResult<()>,
/// println!("input processed: {}", output.unwrap());
/// # }
/// ```
-#[cfg(stage0)]
-pub struct RefWriter<'a, W> {
- /// The underlying writer which this is referencing
- inner: &'a mut W
-}
-
-/// A `RefWriter` is a struct implementing `Writer` which contains a reference
-/// to another writer. This is often useful when composing streams.
-///
-/// # Example
-///
-/// ```
-/// # fn main() {}
-/// # fn process_input<R: Reader>(r: R) {}
-/// # fn foo () {
-/// use std::io::util::TeeReader;
-/// use std::io::{stdin, MemWriter};
-///
-/// let mut output = MemWriter::new();
-///
-/// {
-/// // Don't give ownership of 'output' to the 'tee'. Instead we keep a
-/// // handle to it in the outer scope
-/// let mut tee = TeeReader::new(stdin(), output.by_ref());
-/// process_input(tee);
-/// }
-///
-/// println!("input processed: {}", output.unwrap());
-/// # }
-/// ```
-#[cfg(not(stage0))]
pub struct RefWriter<'a, W:'a> {
/// The underlying writer which this is referencing
inner: &'a mut W
///
/// Any error other than `EndOfFile` that is produced by the underlying Reader
/// is returned by the iterator and should be handled by the caller.
-#[cfg(stage0)]
-pub struct Lines<'r, T> {
- buffer: &'r mut T,
-}
-
-/// An iterator that reads a line on each iteration,
-/// until `.read_line()` encounters `EndOfFile`.
-///
-/// # Notes about the Iteration Protocol
-///
-/// The `Lines` may yield `None` and thus terminate
-/// an iteration, but continue to yield elements if iteration
-/// is attempted again.
-///
-/// # Error
-///
-/// Any error other than `EndOfFile` that is produced by the underlying Reader
-/// is returned by the iterator and should be handled by the caller.
-#[cfg(not(stage0))]
pub struct Lines<'r, T:'r> {
buffer: &'r mut T,
}
///
/// Any error other than `EndOfFile` that is produced by the underlying Reader
/// is returned by the iterator and should be handled by the caller.
-#[cfg(stage0)]
-pub struct Chars<'r, T> {
- buffer: &'r mut T
-}
-
-/// An iterator that reads a utf8-encoded character on each iteration,
-/// until `.read_char()` encounters `EndOfFile`.
-///
-/// # Notes about the Iteration Protocol
-///
-/// The `Chars` may yield `None` and thus terminate
-/// an iteration, but continue to yield elements if iteration
-/// is attempted again.
-///
-/// # Error
-///
-/// Any error other than `EndOfFile` that is produced by the underlying Reader
-/// is returned by the iterator and should be handled by the caller.
-#[cfg(not(stage0))]
pub struct Chars<'r, T:'r> {
buffer: &'r mut T
}
}
}
-/// Note: stage0-specific version that lacks bound on A.
-#[cfg(stage0)]
-pub struct IncomingConnections<'a, A> {
- inc: &'a mut A,
-}
-
/// An infinite iterator over incoming connection attempts.
/// Calling `next` will block the task until a connection is attempted.
///
/// `Some`. The `Some` contains the `IoResult` representing whether the
/// connection attempt was successful. A successful connection will be wrapped
/// in `Ok`. A failed connection is represented as an `Err`.
-#[cfg(not(stage0))]
pub struct IncomingConnections<'a, A:'a> {
inc: &'a mut A,
}
#![feature(macro_rules, globs, managed_boxes, linkage)]
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]
#![feature(import_shadowing)]
-#![feature(issue_5723_bootstrap)]
// Don't link to std. We are std.
#![no_std]
-// NOTE(stage0, pcwalton): Remove after snapshot.
-#![allow(unknown_features)]
-
#![allow(deprecated)]
#![deny(missing_doc)]
#![experimental]
#![allow(missing_doc)]
-#![allow(non_snake_case_functions)]
+#![allow(non_snake_case)]
use clone::Clone;
use collections::{Collection, MutableSeq};
unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T);
}
-/// Note: stage0-specific version that lacks bound.
-#[cfg(stage0)]
-pub struct Display<'a, P> {
- path: &'a P,
- filename: bool
-}
-
/// Helper struct for printing paths with format!()
-#[cfg(not(stage0))]
pub struct Display<'a, P:'a> {
path: &'a P,
filename: bool
static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
static NTE_BAD_SIGNATURE: DWORD = 0x80090006;
- #[allow(non_snake_case_functions)]
+ #[allow(non_snake_case)]
extern "system" {
fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
pszContainer: LPCSTR,
/// iOS doesn't use all of them it but adding more
/// platform-specific configs pollutes the code too much
#[allow(non_camel_case_types)]
- #[allow(non_snake_case_functions)]
+ #[allow(non_snake_case)]
#[allow(dead_code)]
mod uw {
use libc;
/// copy of that function in my mingw install (maybe it was broken?). Instead,
/// this takes the route of using StackWalk64 in order to walk the stack.
#[cfg(windows)]
-#[allow(dead_code, uppercase_variables)]
+#[allow(dead_code, non_snake_case)]
mod imp {
use c_str::CString;
use core_collections::Collection;
use str::StrSlice;
use dynamic_lib::DynamicLibrary;
- #[allow(non_snake_case_functions)]
+ #[allow(non_snake_case)]
extern "system" {
fn GetCurrentProcess() -> libc::HANDLE;
fn GetCurrentThread() -> libc::HANDLE;
static IMAGE_FILE_MACHINE_IA64: libc::DWORD = 0x0200;
static IMAGE_FILE_MACHINE_AMD64: libc::DWORD = 0x8664;
- #[cfg(stage0)]
- #[packed]
- struct SYMBOL_INFO {
- SizeOfStruct: libc::c_ulong,
- TypeIndex: libc::c_ulong,
- Reserved: [u64, ..2],
- Index: libc::c_ulong,
- Size: libc::c_ulong,
- ModBase: u64,
- Flags: libc::c_ulong,
- Value: u64,
- Address: u64,
- Register: libc::c_ulong,
- Scope: libc::c_ulong,
- Tag: libc::c_ulong,
- NameLen: libc::c_ulong,
- MaxNameLen: libc::c_ulong,
- // note that windows has this as 1, but it basically just means that
- // the name is inline at the end of the struct. For us, we just bump
- // the struct size up to MAX_SYM_NAME.
- Name: [libc::c_char, ..MAX_SYM_NAME],
- }
-
- #[cfg(not(stage0))]
#[repr(C, packed)]
struct SYMBOL_INFO {
SizeOfStruct: libc::c_ulong,
/// whenever `next` is called, waiting for a new message, and `None` will be
/// returned when the corresponding channel has hung up.
#[unstable]
-#[cfg(not(stage0))]
pub struct Messages<'a, T:'a> {
rx: &'a Receiver<T>
}
-/// Stage0 only
-#[cfg(stage0)]
-#[unstable]
-pub struct Messages<'a, T> {
- rx: &'a Receiver<T>
-}
-
/// The sending-half of Rust's asynchronous channel type. This half can only be
/// owned by one task, but it can be cloned to send to other tasks.
#[unstable]
/// A handle to a receiver which is currently a member of a `Select` set of
/// receivers. This handle is used to keep the receiver in the set as well as
/// interact with the underlying receiver.
-#[cfg(not(stage0))]
pub struct Handle<'rx, T:'rx> {
/// The ID of this handle, used to compare against the return value of
/// `Select::wait()`
rx: &'rx Receiver<T>,
}
-/// Stage0 only
-#[cfg(stage0)]
-pub struct Handle<'rx, T> {
- /// The ID of this handle, used to compare against the return value of
- /// `Select::wait()`
- id: uint,
- selector: &'rx Select,
- next: *mut Handle<'static, ()>,
- prev: *mut Handle<'static, ()>,
- added: bool,
- packet: &'rx Packet+'rx,
-
- // due to our fun transmutes, we be sure to place this at the end. (nothing
- // previous relies on T)
- rx: &'rx Receiver<T>,
-}
-
struct Packets { cur: *mut Handle<'static, ()> }
#[doc(hidden)]
#![feature(phase, globs, macro_rules, unsafe_destructor)]
#![feature(import_shadowing)]
-#![feature(issue_5723_bootstrap)]
#![deny(missing_doc)]
#![no_std]
-// NOTE(stage0, pcwalton): Remove after snapshot.
-#![allow(unknown_features)]
-
#[phase(plugin, link)] extern crate core;
extern crate alloc;
extern crate collections;
/// An guard which is created by locking a mutex. Through this guard the
/// underlying data can be accessed.
-#[cfg(not(stage0))]
pub struct MutexGuard<'a, T:'a> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
pub cond: Condvar<'a>,
}
-/// stage0 only
-#[cfg(stage0)]
-pub struct MutexGuard<'a, T> {
- // FIXME #12808: strange name to try to avoid interfering with
- // field accesses of the contained type via Deref
- _data: &'a mut T,
- /// Inner condition variable connected to the locked mutex that this guard
- /// was created from. This can be used for atomic-unlock-and-deschedule.
- pub cond: Condvar<'a>,
-}
-
impl<T: Send> Mutex<T> {
/// Creates a new mutex to protect the user-supplied data.
pub fn new(user_data: T) -> Mutex<T> {
/// A guard which is created by locking an rwlock in write mode. Through this
/// guard the underlying data can be accessed.
-#[cfg(not(stage0))]
pub struct RWLockWriteGuard<'a, T:'a> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
pub cond: Condvar<'a>,
}
-/// stage0 only
-#[cfg(stage0)]
-pub struct RWLockWriteGuard<'a, T> {
- // FIXME #12808: strange name to try to avoid interfering with
- // field accesses of the contained type via Deref
- _data: &'a mut T,
- /// Inner condition variable that can be used to sleep on the write mode of
- /// this rwlock.
- pub cond: Condvar<'a>,
-}
-
/// A guard which is created by locking an rwlock in read mode. Through this
/// guard the underlying data can be accessed.
-#[cfg(not(stage0))]
pub struct RWLockReadGuard<'a, T:'a> {
// FIXME #12808: strange names to try to avoid interfering with
// field accesses of the contained type via Deref
_guard: raw::RWLockReadGuard<'a>,
}
-/// Stage0 only
-#[cfg(stage0)]
-pub struct RWLockReadGuard<'a, T> {
- // FIXME #12808: strange names to try to avoid interfering with
- // field accesses of the contained type via Deref
- _data: &'a T,
- _guard: raw::RWLockReadGuard<'a>,
-}
-
impl<T: Send + Sync> RWLock<T> {
/// Create a reader/writer lock with the supplied data.
pub fn new(user_data: T) -> RWLock<T> {
}
#[must_use]
-#[cfg(stage0)]
-struct SemGuard<'a, Q> {
- sem: &'a Sem<Q>,
-}
-
-#[must_use]
-#[cfg(not(stage0))]
struct SemGuard<'a, Q:'a> {
sem: &'a Sem<Q>,
}
}
}
-#[allow(non_snake_case_functions)]
+#[allow(non_snake_case)]
#[test]
fn lookup_Rust() {
let abi = lookup("Rust");
// FIXME(eddyb) #10676 use Rc<T> in the future.
pub type P<T> = Gc<T>;
-#[allow(non_snake_case_functions)]
+#[allow(non_snake_case)]
/// Construct a P<T> from a T value.
pub fn P<T: 'static>(value: T) -> P<T> {
box(GC) value
ExprLit(Gc<Lit>),
ExprCast(Gc<Expr>, P<Ty>),
ExprIf(Gc<Expr>, P<Block>, Option<Gc<Expr>>),
- ExprWhile(Gc<Expr>, P<Block>),
+ // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
+ ExprWhile(Gc<Expr>, P<Block>, Option<Ident>),
// FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
ExprForLoop(Gc<Pat>, Gc<Expr>, P<Block>, Option<Ident>),
// Conditionless loop (can be exited with break, cont, or ret)
}
}
-#[cfg(stage0)]
-#[deriving(Clone)]
-pub struct Values<'a, T>(pub slice::Items<'a, T>);
-
// HACK(eddyb) move this into libstd (value wrapper for slice::Items).
-#[cfg(not(stage0))]
#[deriving(Clone)]
pub struct Values<'a, T:'a>(pub slice::Items<'a, T>);
}
}
-#[cfg(stage0)]
-pub struct NodesMatchingSuffix<'a, S> {
- map: &'a Map,
- item_name: &'a S,
- in_which: &'a [S],
- idx: NodeId,
-}
-
-#[cfg(not(stage0))]
pub struct NodesMatchingSuffix<'a, S:'a> {
map: &'a Map,
item_name: &'a S,
/// A visitor that applies its operation to all of the node IDs
/// in a visitable thing.
-#[cfg(stage0)]
-pub struct IdVisitor<'a, O> {
- pub operation: &'a O,
- pub pass_through_items: bool,
- pub visited_outermost: bool,
-}
-
-#[cfg(not(stage0))]
pub struct IdVisitor<'a, O:'a> {
pub operation: &'a O,
pub pass_through_items: bool,
}
}
+ ast::ExprWhile(cond, body, opt_ident) => {
+ let cond = fld.fold_expr(cond);
+ let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
+ fld.cx.expr(e.span, ast::ExprWhile(cond, body, opt_ident))
+ }
+
ast::ExprLoop(loop_block, opt_ident) => {
let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
fld.cx.expr(e.span, ast::ExprLoop(loop_block, opt_ident))
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
folder.fold_block(tr),
fl.map(|x| folder.fold_expr(x)))
}
- ExprWhile(cond, body) => {
- ExprWhile(folder.fold_expr(cond), folder.fold_block(body))
+ ExprWhile(cond, body, opt_ident) => {
+ ExprWhile(folder.fold_expr(cond),
+ folder.fold_block(body),
+ opt_ident.map(|i| folder.fold_ident(i)))
}
- ExprForLoop(pat, iter, body, ref maybe_ident) => {
+ ExprForLoop(pat, iter, body, ref opt_ident) => {
ExprForLoop(folder.fold_pat(pat),
folder.fold_expr(iter),
folder.fold_block(body),
- maybe_ident.map(|i| folder.fold_ident(i)))
+ opt_ident.map(|i| folder.fold_ident(i)))
}
ExprLoop(body, opt_ident) => {
ExprLoop(folder.fold_block(body),
- opt_ident.map(|x| folder.fold_ident(x)))
+ opt_ident.map(|i| folder.fold_ident(i)))
}
ExprMatch(expr, ref arms) => {
ExprMatch(folder.fold_expr(expr),
#![feature(macro_rules, globs, managed_boxes, default_type_params, phase)]
#![feature(quote, struct_variant, unsafe_destructor, import_shadowing)]
-#![feature(issue_5723_bootstrap)]
#![allow(deprecated)]
-// NOTE(stage0, pcwalton): Remove after snapshot.
-#![allow(unknown_features)]
-
extern crate fmt_macros;
extern crate debug;
#[phase(plugin, link)] extern crate log;
return self.parse_for_expr(None);
}
if self.eat_keyword(keywords::While) {
- return self.parse_while_expr();
+ return self.parse_while_expr(None);
}
if Parser::token_is_lifetime(&self.token) {
let lifetime = self.get_lifetime();
self.bump();
self.expect(&token::COLON);
+ if self.eat_keyword(keywords::While) {
+ return self.parse_while_expr(Some(lifetime))
+ }
if self.eat_keyword(keywords::For) {
return self.parse_for_expr(Some(lifetime))
}
if self.eat_keyword(keywords::Loop) {
return self.parse_loop_expr(Some(lifetime))
}
- self.fatal("expected `for` or `loop` after a label")
+ self.fatal("expected `while`, `for`, or `loop` after a label")
}
if self.eat_keyword(keywords::Loop) {
return self.parse_loop_expr(None);
self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))
}
- pub fn parse_while_expr(&mut self) -> Gc<Expr> {
+ pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>) -> Gc<Expr> {
let lo = self.last_span.lo;
let cond = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
let body = self.parse_block();
let hi = body.span.hi;
- return self.mk_expr(lo, hi, ExprWhile(cond, body));
+ return self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident));
}
pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>) -> Gc<Expr> {
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
use std::mem;
pub enum AnnNode<'a> {
+ NodeIdent(&'a ast::Ident),
+ NodeName(&'a ast::Name),
NodeBlock(&'a ast::Block),
NodeItem(&'a ast::Item),
NodeExpr(&'a ast::Expr),
ast::ExprIf(ref test, ref blk, elseopt) => {
try!(self.print_if(&**test, &**blk, elseopt, false));
}
- ast::ExprWhile(ref test, ref blk) => {
+ ast::ExprWhile(ref test, ref blk, opt_ident) => {
+ for ident in opt_ident.iter() {
+ try!(self.print_ident(*ident));
+ try!(self.word_space(":"));
+ }
try!(self.head("while"));
try!(self.print_expr(&**test));
try!(space(&mut self.s));
pub fn print_ident(&mut self, ident: ast::Ident) -> IoResult<()> {
if self.encode_idents_with_hygiene {
let encoded = ident.encode_with_hygiene();
- word(&mut self.s, encoded.as_slice())
+ try!(word(&mut self.s, encoded.as_slice()))
} else {
- word(&mut self.s, token::get_ident(ident).get())
+ try!(word(&mut self.s, token::get_ident(ident).get()))
}
+ self.ann.post(self, NodeIdent(&ident))
}
pub fn print_name(&mut self, name: ast::Name) -> IoResult<()> {
- word(&mut self.s, token::get_name(name).get())
+ try!(word(&mut self.s, token::get_name(name).get()));
+ self.ann.post(self, NodeName(&name))
}
pub fn print_for_decl(&mut self, loc: &ast::Local,
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
visitor.visit_block(&**if_block, env.clone());
walk_expr_opt(visitor, optional_else, env.clone())
}
- ExprWhile(ref subexpression, ref block) => {
+ ExprWhile(ref subexpression, ref block, _) => {
visitor.visit_expr(&**subexpression, env.clone());
visitor.visit_block(&**block, env.clone())
}
background: color::Color,
}
-#[allow(non_snake_case_functions)]
+#[allow(non_snake_case)]
#[link(name = "kernel32")]
extern "system" {
fn SetConsoleTextAttribute(handle: libc::HANDLE, attr: libc::WORD) -> libc::BOOL;
// NOTE: The following code was generated by "src/etc/unicode.py", do not edit directly
-#![allow(missing_doc, non_uppercase_statics, non_snake_case_functions)]
+#![allow(missing_doc, non_uppercase_statics, non_snake_case)]
fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
use core::cmp::{Equal, Less, Greater};
/// 'XID_Start' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to ID_Start but modified for closure under NFKx.
-#[allow(non_snake_case_functions)]
+#[allow(non_snake_case)]
pub fn is_XID_start(c: char) -> bool { derived_property::XID_Start(c) }
/// Returns whether the specified `char` satisfies the 'XID_Continue' Unicode property
/// 'XID_Continue' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to 'ID_Continue' but modified for closure under NFKx.
-#[allow(non_snake_case_functions)]
+#[allow(non_snake_case)]
pub fn is_XID_continue(c: char) -> bool { derived_property::XID_Continue(c) }
///
/// 'XID_Start' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to ID_Start but modified for closure under NFKx.
- #[allow(non_snake_case_functions)]
+ #[allow(non_snake_case)]
fn is_XID_start(&self) -> bool;
/// Returns whether the specified `char` satisfies the 'XID_Continue'
/// 'XID_Continue' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
/// mostly similar to 'ID_Continue' but modified for closure under NFKx.
- #[allow(non_snake_case_functions)]
+ #[allow(non_snake_case)]
fn is_XID_continue(&self) -> bool;
+S 2014-08-29 6025926
+ freebsd-x86_64 285330b798eefcc929fc94c9d0604b6172ce3309
+ linux-i386 5b57ab2dc32952dc78551a955f3c1746b2d915a3
+ linux-x86_64 2624aeac3fe1b2359b61c1109e4708680e237ca5
+ macos-i386 deffce32408b023bcda84f6ce338ca3de02f406b
+ macos-x86_64 8ef7351e34fc1583570d752d223ddc6eb68ef27b
+ winnt-i386 c2dfa9a358de8cc554007addbc09e3e43d49aec6
+
S 2014-08-17 a86d9ad
freebsd-x86_64 f49e0c8e64c8a60dc47df9965974d2a98ef70b34
linux-i386 8f2c5f6a1b6504ee63de73c7a53aee1e4b07bca5
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// force-host
+
+#![feature(phase, plugin_registrar)]
+
+extern crate syntax;
+
+// Load rustc as a plugin to get macros
+#[phase(plugin, link)]
+extern crate rustc;
+
+use syntax::ast;
+use syntax::parse::token;
+use rustc::lint::{Context, LintPass, LintPassObject, LintArray};
+use rustc::plugin::Registry;
+
+declare_lint!(TEST_LINT, Warn,
+ "Warn about items named 'lintme'")
+
+declare_lint!(PLEASE_LINT, Warn,
+ "Warn about items named 'pleaselintme'")
+
+struct Pass;
+
+impl LintPass for Pass {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(TEST_LINT, PLEASE_LINT)
+ }
+
+ fn check_item(&mut self, cx: &Context, it: &ast::Item) {
+ let name = token::get_ident(it.ident);
+ if name.get() == "lintme" {
+ cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
+ } else if name.get() == "pleaselintme" {
+ cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'");
+ }
+ }
+}
+
+#[plugin_registrar]
+pub fn plugin_registrar(reg: &mut Registry) {
+ reg.register_lint_pass(box Pass as LintPassObject);
+ reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]);
+}
// no-pretty-expanded FIXME #15189
#![feature(phase)]
-#![allow(non_snake_case_functions)]
+#![allow(non_snake_case)]
#[phase(plugin)] extern crate green;
use std::from_str::FromStr;
// ignore-pretty very bad with line comments
-#![allow(non_snake_case_functions)]
+#![allow(non_snake_case)]
use std::io;
use std::io::stdio::StdReader;
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:lint_group_plugin_test.rs
+// ignore-stage1
+// compile-flags: -D lint-me
+
+#![feature(phase)]
+
+#[phase(plugin)]
+extern crate lint_group_plugin_test;
+
+fn lintme() { } //~ ERROR item is named 'lintme'
+
+fn pleaselintme() { } //~ ERROR item is named 'pleaselintme'
+
+pub fn main() {
+ lintme();
+ pleaselintme();
+}
let c1 = || set(&mut *x);
//~^ ERROR cannot borrow
let c2 = || set(&mut *x);
- //~^ ERROR closure requires unique access to `x`
- //~^^ ERROR cannot borrow
+ //~^ ERROR cannot borrow
}
fn main() {
fn copy_borrowed_ptr<'a,'b>(p: &'a mut S<'b>) -> S<'b> {
S { pointer: &mut *p.pointer }
- //~^ ERROR lifetime of `p` is too short to guarantee its contents can be safely reborrowed
+ //~^ ERROR cannot infer
}
fn main() {
x: 1,
y: 2,
};
- for x in bogus { //~ ERROR does not implement the `Iterator` trait
+ for x in bogus { //~ ERROR has type `MyStruct` which does not implement the `Iterator` trait
drop(x);
}
}
-
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn main() {
+ let x = () + (); //~ ERROR binary operation
+
+ // this shouldn't have a flow-on error:
+ for _ in x {}
+}
// except according to those terms.
fn test<'x>(x: &'x int) {
- drop::< <'z>|&'z int| -> &'z int>(|z| {
+ drop::< <'z>|&'z int| -> &'z int >(|z| {
x
//~^ ERROR cannot infer an appropriate lifetime
});
let x = [1,2];
let y = match x {
[] => None,
-//~^ ERROR expected `[<generic integer #1>, .. 2]`, found a fixed vector pattern of size 0
+//~^ ERROR expected `[<generic integer #0>, .. 2]`, found a fixed vector pattern of size 0
[a,_] => Some(a)
};
}
fn main() {
let Slice { data: data, len: len } = "foo";
- //~^ ERROR mismatched types: expected `&'static str`, found a structure pattern
+ //~^ ERROR mismatched types: expected `&str`, found a structure pattern
}
}
fn main() {
["hi"].bind(|x| [x] );
- //~^ ERROR type `[&'static str, .. 1]` does not implement any method in scope named `bind`
+ //~^ ERROR type `[&str, .. 1]` does not implement any method in scope named `bind`
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that Copy bounds inherited by trait are checked.
+
+use std::any::Any;
+use std::any::AnyRefExt;
+
+trait Foo : Copy {
+}
+
+impl<T:Copy> Foo for T {
+}
+
+fn take_param<T:Foo>(foo: &T) { }
+
+fn main() {
+ let x = box 3i;
+ take_param(&x); //~ ERROR does not fulfill `Copy`
+
+ let y = &x;
+ let z = &x as &Foo; //~ ERROR does not fulfill `Copy`
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test which object types are considered sendable. This test
+// is broken into two parts because some errors occur in distinct
+// phases in the compiler. See kindck-send-object2.rs as well!
+
+fn assert_send<T:Send>() { }
+trait Dummy { }
+
+// careful with object types, who knows what they close over...
+fn test51<'a>() {
+ assert_send::<&'a Dummy>(); //~ ERROR does not fulfill the required lifetime
+}
+fn test52<'a>() {
+ assert_send::<&'a Dummy+Send>(); //~ ERROR does not fulfill the required lifetime
+}
+
+// ...unless they are properly bounded
+fn test60() {
+ assert_send::<&'static Dummy+Send>();
+}
+fn test61() {
+ assert_send::<Box<Dummy+Send>>();
+}
+
+// closure and object types can have lifetime bounds which make
+// them not ok
+fn test_70<'a>() {
+ assert_send::<proc():'a>(); //~ ERROR does not fulfill the required lifetime
+}
+
+fn test_71<'a>() {
+ assert_send::<Box<Dummy+'a>>(); //~ ERROR does not fulfill the required lifetime
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Continue kindck-send-object1.rs.
+
+fn assert_send<T:Send>() { }
+trait Dummy { }
+
+fn test50() {
+ assert_send::<&'static Dummy>(); //~ ERROR does not fulfill `Send`
+}
+
+fn test53() {
+ assert_send::<Box<Dummy>>(); //~ ERROR does not fulfill `Send`
+}
+
+// ...unless they are properly bounded
+fn test60() {
+ assert_send::<&'static Dummy+Send>();
+}
+fn test61() {
+ assert_send::<Box<Dummy+Send>>();
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test which of the builtin types are considered sendable.
+
+fn assert_send<T:Send>() { }
+
+// owned content are ok
+fn test30() { assert_send::<Box<int>>(); }
+fn test31() { assert_send::<String>(); }
+fn test32() { assert_send::<Vec<int> >(); }
+
+// but not if they own a bad thing
+fn test40<'a>(_: &'a int) {
+ assert_send::<Box<&'a int>>(); //~ ERROR does not fulfill the required lifetime
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that borrowed pointers are not sendable unless 'static.
+
+fn assert_send<T:Send>() { }
+
+// lifetime pointers with 'static lifetime are ok
+fn test01() { assert_send::<&'static int>(); }
+fn test02() { assert_send::<&'static str>(); }
+fn test03() { assert_send::<&'static [int]>(); }
+
+// whether or not they are mutable
+fn test10() { assert_send::<&'static mut int>(); }
+
+// otherwise lifetime pointers are not ok
+fn test20<'a>(_: &'a int) {
+ assert_send::<&'a int>(); //~ ERROR does not fulfill the required lifetime
+}
+fn test21<'a>(_: &'a int) {
+ assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
+}
+fn test22<'a>(_: &'a int) {
+ assert_send::<&'a [int]>(); //~ ERROR does not fulfill the required lifetime
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn assert_send<T:Send>() { }
+
+// unsafe ptrs are ok unless they point at unsendable things
+fn test70() {
+ assert_send::<*mut int>();
+}
+fn test71<'a>() {
+ assert_send::<*mut &'a int>(); //~ ERROR does not fulfill the required lifetime
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(bad_style)]
+//~^ NOTE lint level defined here
+#![allow(dead_code)]
+
+fn CamelCase() {} //~ ERROR function `CamelCase` should have a snake case name
+
+#[allow(bad_style)]
+mod test {
+ fn CamelCase() {}
+
+ #[forbid(bad_style)]
+ //~^ NOTE lint level defined here
+ //~^^ NOTE lint level defined here
+ mod bad {
+ fn CamelCase() {} //~ ERROR function `CamelCase` should have a snake case name
+
+ static bad: int = 1; //~ ERROR static constant `bad` should have an uppercase name
+ }
+
+ mod warn {
+ #![warn(bad_style)]
+ //~^ NOTE lint level defined here
+
+ fn CamelCase() {} //~ WARN function `CamelCase` should have a snake case name
+
+ struct snake_case; //~ WARN type `snake_case` should have a camel case name
+ }
+}
+
+fn main() {}
trait foo6 { //~ ERROR trait `foo6` should have a camel case name such as `Foo6`
}
+fn f<ty>(_: ty) {} //~ ERROR type parameter `ty` should have a camel case name such as `Ty`
+
#[repr(C)]
struct foo7 {
bar: int,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![deny(non_snake_case_functions)]
+#![deny(non_snake_case)]
#![allow(dead_code)]
struct Foo;
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(non_snake_case)]
+#![allow(dead_code)]
+
+fn f<'FooBar>( //~ ERROR lifetime `'FooBar` should have a snake case name such as `'foo_bar`
+ _: &'FooBar ()
+) {}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(non_snake_case)]
+#![allow(dead_code)]
+
+mod FooBar { //~ ERROR module `FooBar` should have a snake case name such as `foo_bar`
+ pub struct S;
+}
+
+fn f(_: FooBar::S) { }
+
+fn main() { }
// ignore-tidy-linelength
#![allow(dead_code)]
-#![deny(uppercase_variables)]
+#![deny(non_snake_case)]
use std::io::File;
use std::io::IoError;
struct Something {
- X: uint //~ ERROR structure field names should start with a lowercase character
+ X: uint //~ ERROR structure field `X` should have a snake case name such as `x`
}
-fn test(Xx: uint) { //~ ERROR variable names should start with a lowercase character
+fn test(Xx: uint) { //~ ERROR variable `Xx` should have a snake case name such as `xx`
println!("{}", Xx);
}
fn main() {
- let Test: uint = 0; //~ ERROR variable names should start with a lowercase character
+ let Test: uint = 0; //~ ERROR variable `Test` should have a snake case name such as `test`
println!("{}", Test);
let mut f = File::open(&Path::new("something.txt"));
match f.read(buff) {
Ok(cnt) => println!("read this many bytes: {}", cnt),
Err(IoError{ kind: EndOfFile, .. }) => println!("Got end of file: {}", EndOfFile.to_string()),
- //~^ ERROR variable names should start with a lowercase character
+ //~^ ERROR variable `EndOfFile` should have a snake case name such as `end_of_file`
}
test(1);
// Issue #7526: lowercase static constants in patterns look like bindings
#![allow(dead_code)]
-#![deny(non_uppercase_pattern_statics)]
+#![deny(non_uppercase_statics)]
+#[allow(non_uppercase_statics)]
pub static a : int = 97;
fn f() {
}
mod m {
+ #[allow(non_uppercase_statics)]
pub static aha : int = 7;
}
fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> {
return e; //~ ERROR mismatched types: expected `an_enum<'b>`, found `an_enum<'a>`
- //~^ ERROR cannot infer
}
fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> {
return e; //~ ERROR mismatched types: expected `a_class<'b>`, found `a_class<'a>`
- //~^ ERROR cannot infer
}
fn main() { }
fn main() {
let mut x = None;
- //~^ ERROR lifetime of variable does not enclose its declaration
- //~^^ ERROR type of expression contains references that are not valid during the expression
with_int(|y| x = Some(y));
+ //~^ ERROR cannot infer
}
}
fn main() {
- let mut x: Option<&int> = None; //~ ERROR cannot infer
- with_int(|y| x = Some(y));
+ let mut x: Option<&int> = None;
+ with_int(|y| x = Some(y)); //~ ERROR cannot infer
}
}
fn return_it() -> int {
- with(|o| o) //~ ERROR cannot infer an appropriate lifetime
+ with(|o| o) //~ ERROR cannot infer
}
fn main() {
fn take1<'a>(p: parameterized1) -> parameterized1<'a> { p }
//~^ ERROR mismatched types
-//~^^ ERROR cannot infer
fn take3(p: not_parameterized1) -> not_parameterized1 { p }
fn take4(p: not_parameterized2) -> not_parameterized2 { p }
// covariant with respect to its parameter 'a.
let _: Contravariant<'long> = c; //~ ERROR mismatched types
- //~^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
// contravariant with respect to its parameter 'a.
let _: Covariant<'short> = c; //~ ERROR mismatched types
- //~^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
}
fn take_direct<'a,'b>(p: direct<'a>) -> direct<'b> { p } //~ ERROR mismatched types
-//~^ ERROR cannot infer
fn take_indirect1(p: indirect1) -> indirect1 { p }
fn take_indirect2<'a,'b>(p: indirect2<'a>) -> indirect2<'b> { p } //~ ERROR mismatched types
-//~^ ERROR cannot infer
fn main() {}
}
trait set_f<'a> {
- fn set_f_ok(&self, b: Gc<b<'a>>);
- fn set_f_bad(&self, b: Gc<b>);
+ fn set_f_ok(&mut self, b: Gc<b<'a>>);
+ fn set_f_bad(&mut self, b: Gc<b>);
}
impl<'a> set_f<'a> for c<'a> {
- fn set_f_ok(&self, b: Gc<b<'a>>) {
+ fn set_f_ok(&mut self, b: Gc<b<'a>>) {
self.f = b;
}
- fn set_f_bad(&self, b: Gc<b>) {
+ fn set_f_bad(&mut self, b: Gc<b>) {
self.f = b; //~ ERROR mismatched types: expected `Gc<Gc<&'a int>>`, found `Gc<Gc<&int>>`
- //~^ ERROR cannot infer
}
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that, when a variable of type `&T` is captured inside a proc,
+// we correctly infer/require that its lifetime is 'static.
+
+fn foo(_p: proc():'static) { }
+
+static i: int = 3;
+
+fn capture_local() {
+ let x = 3i;
+ let y = &x; //~ ERROR `x` does not live long enough
+ foo(proc() {
+ let _a = *y;
+ });
+}
+
+fn capture_static() {
+ // Legal because &i can have static lifetime:
+ let y = &i;
+ foo(proc() {
+ let _a = *y;
+ });
+}
+
+fn main() { }
// Issue #8624. Test for reborrowing with 3 levels, not just two.
fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut int) -> &'b mut int {
- &mut ***p //~ ERROR lifetime of `p` is too short to guarantee its contents
+ &mut ***p //~ ERROR cannot infer
}
fn main() {
// for `'a` (which must be a sublifetime of `'b`).
fn copy_borrowed_ptr<'a, 'b>(p: &'a mut &'b mut int) -> &'b mut int {
- &mut **p //~ ERROR lifetime of `p` is too short
+ &mut **p //~ ERROR cannot infer
}
fn main() {
fn return_it<'a>() -> &'a int {
with(|o| o)
//~^ ERROR cannot infer
- //~^^ ERROR not valid during the expression
- //~^^^ ERROR not valid at this point
}
fn main() {
fn return_it<'a>() -> &'a int {
with(|o| o)
//~^ ERROR cannot infer
- //~^^ ERROR not valid during the expression
- //~^^^ ERROR not valid at this point
}
fn main() {
// covariant with respect to its parameter 'a.
let _: S<'long, 'long> = c; //~ ERROR mismatched types
- //~^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
// covariant with respect to its parameter 'a.
let _: Contravariant<'long> = c; //~ ERROR mismatched types
- //~^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
// contravariant with respect to its parameter 'a.
let _: Covariant<'short> = c; //~ ERROR mismatched types
- //~^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::slice as std; //~ ERROR import conflicts with imported crate
+use std::slice as std; //~ ERROR import `std` conflicts with imported crate
fn main() {
}
// except according to those terms.
use std::mem::transmute;
-//~^ ERROR import conflicts with value in this module
+//~^ ERROR import `transmute` conflicts with value in this module
fn transmute() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::slice::Items;
+//~^ ERROR import `Items` conflicts with type in this module
+
+struct Items;
+
+fn main() {
+}
+
--- /dev/null
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test uses only GDB Python API features which should be available in
+// older versions of GDB too. A more extensive test can be found in
+// gdb-pretty-struct-and-enums.rs
+
+// ignore-tidy-linelength
+// ignore-lldb
+// ignore-android: FIXME(#10381)
+// compile-flags:-g
+// gdb-use-pretty-printer
+
+// The following line actually doesn't have to do anything with pretty printing,
+// it just tells GDB to print values on one line:
+// gdb-command: set print pretty off
+
+// gdb-command: rbreak zzz
+// gdb-command: run
+// gdb-command: finish
+
+// gdb-command: print regular_struct
+// gdb-check:$1 = RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false}
+
+// gdb-command: print empty_struct
+// gdb-check:$2 = EmptyStruct
+
+// gdb-command: print c_style_enum1
+// gdb-check:$3 = CStyleEnumVar1
+
+// gdb-command: print c_style_enum2
+// gdb-check:$4 = CStyleEnumVar2
+
+// gdb-command: print c_style_enum3
+// gdb-check:$5 = CStyleEnumVar3
+
+struct RegularStruct {
+ the_first_field: int,
+ the_second_field: f64,
+ the_third_field: bool,
+}
+
+struct EmptyStruct;
+
+enum CStyleEnum {
+ CStyleEnumVar1,
+ CStyleEnumVar2,
+ CStyleEnumVar3,
+}
+
+fn main() {
+
+ let regular_struct = RegularStruct {
+ the_first_field: 101,
+ the_second_field: 102.5,
+ the_third_field: false
+ };
+
+ let empty_struct = EmptyStruct;
+
+ let c_style_enum1 = CStyleEnumVar1;
+ let c_style_enum2 = CStyleEnumVar2;
+ let c_style_enum3 = CStyleEnumVar3;
+
+ zzz();
+}
+
+fn zzz() { () }
--- /dev/null
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// ignore-lldb
+// ignore-android: FIXME(#10381)
+// compile-flags:-g
+// gdb-use-pretty-printer
+
+// This test uses some GDB Python API features (e.g. accessing anonymous fields)
+// which are only available in newer GDB version. The following directive will
+// case the test runner to ignore this test if an older GDB version is used:
+// min-gdb-version 7.7
+
+// The following line actually doesn't have to do anything with pretty printing,
+// it just tells GDB to print values on one line:
+// gdb-command: set print pretty off
+
+// gdb-command: rbreak zzz
+// gdb-command: run
+// gdb-command: finish
+
+// gdb-command: print regular_struct
+// gdb-check:$1 = RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false, the_fourth_field = "I'm so pretty, oh so pretty..."}
+
+// gdb-command: print tuple
+// gdb-check:$2 = {true, 103, "blub"}
+
+// gdb-command: print tuple_struct
+// gdb-check:$3 = TupleStruct = {-104.5, 105}
+
+// gdb-command: print empty_struct
+// gdb-check:$4 = EmptyStruct
+
+// gdb-command: print c_style_enum1
+// gdb-check:$5 = CStyleEnumVar1
+
+// gdb-command: print c_style_enum2
+// gdb-check:$6 = CStyleEnumVar2
+
+// gdb-command: print c_style_enum3
+// gdb-check:$7 = CStyleEnumVar3
+
+// gdb-command: print mixed_enum_c_style_var
+// gdb-check:$8 = MixedEnumCStyleVar
+
+// gdb-command: print mixed_enum_tuple_var
+// gdb-check:$9 = MixedEnumTupleVar = {106, 107, false}
+
+// gdb-command: print mixed_enum_struct_var
+// gdb-check:$10 = MixedEnumStructVar = {field1 = 108.5, field2 = 109}
+
+// gdb-command: print some
+// gdb-check:$11 = Some = {110}
+
+// gdb-command: print none
+// gdb-check:$12 = None
+
+// gdb-command: print nested_variant1
+// gdb-check:$13 = NestedVariant1 = {NestedStruct = {regular_struct = RegularStruct = {the_first_field = 111, the_second_field = 112.5, the_third_field = true, the_fourth_field = "NestedStructString1"}, tuple_struct = TupleStruct = {113.5, 114}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar2, mixed_enum = MixedEnumTupleVar = {115, 116, false}}}
+
+// gdb-command: print nested_variant2
+// gdb-check:$14 = NestedVariant2 = {abc = NestedStruct = {regular_struct = RegularStruct = {the_first_field = 117, the_second_field = 118.5, the_third_field = false, the_fourth_field = "NestedStructString10"}, tuple_struct = TupleStruct = {119.5, 120}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar3, mixed_enum = MixedEnumStructVar = {field1 = 121.5, field2 = -122}}}
+
+#![feature(struct_variant)]
+
+struct RegularStruct {
+ the_first_field: int,
+ the_second_field: f64,
+ the_third_field: bool,
+ the_fourth_field: &'static str,
+}
+
+struct TupleStruct(f64, i16);
+
+struct EmptyStruct;
+
+enum CStyleEnum {
+ CStyleEnumVar1,
+ CStyleEnumVar2,
+ CStyleEnumVar3,
+}
+
+enum MixedEnum {
+ MixedEnumCStyleVar,
+ MixedEnumTupleVar(u32, u16, bool),
+ MixedEnumStructVar { field1: f64, field2: i32 }
+}
+
+struct NestedStruct {
+ regular_struct: RegularStruct,
+ tuple_struct: TupleStruct,
+ empty_struct: EmptyStruct,
+ c_style_enum: CStyleEnum,
+ mixed_enum: MixedEnum,
+}
+
+enum NestedEnum {
+ NestedVariant1(NestedStruct),
+ NestedVariant2 { abc: NestedStruct }
+}
+
+fn main() {
+
+ let regular_struct = RegularStruct {
+ the_first_field: 101,
+ the_second_field: 102.5,
+ the_third_field: false,
+ the_fourth_field: "I'm so pretty, oh so pretty..."
+ };
+
+ let tuple = ( true, 103u32, "blub" );
+
+ let tuple_struct = TupleStruct(-104.5, 105);
+
+ let empty_struct = EmptyStruct;
+
+ let c_style_enum1 = CStyleEnumVar1;
+ let c_style_enum2 = CStyleEnumVar2;
+ let c_style_enum3 = CStyleEnumVar3;
+
+ let mixed_enum_c_style_var = MixedEnumCStyleVar;
+ let mixed_enum_tuple_var = MixedEnumTupleVar(106, 107, false);
+ let mixed_enum_struct_var = MixedEnumStructVar { field1: 108.5, field2: 109 };
+
+ let some = Some(110u);
+ let none: Option<int> = None;
+
+ let nested_variant1 = NestedVariant1(
+ NestedStruct {
+ regular_struct: RegularStruct {
+ the_first_field: 111,
+ the_second_field: 112.5,
+ the_third_field: true,
+ the_fourth_field: "NestedStructString1",
+ },
+ tuple_struct: TupleStruct(113.5, 114),
+ empty_struct: EmptyStruct,
+ c_style_enum: CStyleEnumVar2,
+ mixed_enum: MixedEnumTupleVar(115, 116, false)
+ }
+ );
+
+ let nested_variant2 = NestedVariant2 {
+ abc: NestedStruct {
+ regular_struct: RegularStruct {
+ the_first_field: 117,
+ the_second_field: 118.5,
+ the_third_field: false,
+ the_fourth_field: "NestedStructString10",
+ },
+ tuple_struct: TupleStruct(119.5, 120),
+ empty_struct: EmptyStruct,
+ c_style_enum: CStyleEnumVar3,
+ mixed_enum: MixedEnumStructVar {
+ field1: 121.5,
+ field2: -122
+ }
+ }
+ };
+
+ zzz();
+}
+
+fn zzz() { () }
--- /dev/null
+-include ../tools.mk
+
+REPLACEMENT := s/[0-9][0-9]*\#[0-9][0-9]*/$(shell date)/g
+
+all:
+ $(RUSTC) -o $(TMPDIR)/input.out --pretty expanded,hygiene input.rs
+
+ # the name/ctxt numbers are very internals-dependent and thus
+ # change relatively frequently, and testing for their exact values
+ # them will fail annoyingly, so we just check their positions
+ # (using a non-constant replacement like this will make it less
+ # likely the compiler matches whatever other dummy value we
+ # choose).
+ #
+ # (These need to be out-of-place because OSX/BSD & GNU sed
+ # differ.)
+ sed "$(REPLACEMENT)" input.pp.rs > $(TMPDIR)/input.pp.rs
+ sed "$(REPLACEMENT)" $(TMPDIR)/input.out > $(TMPDIR)/input.out.replaced
+
+ diff -u $(TMPDIR)/input.out.replaced $(TMPDIR)/input.pp.rs
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(macro_rules)]
+// minimal junk
+#![no_std]
+
+
+fn bar /* 62#0 */() { let x /* 59#2 */ = 1; y /* 61#4 */ + x /* 59#5 */ }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(macro_rules)]
+// minimal junk
+#![no_std]
+
+macro_rules! foo {
+ ($x: ident) => { y + $x }
+}
+
+fn bar() {
+ let x = 1;
+ foo!(x)
+}
--- /dev/null
+-include ../tools.mk
+
+# FIXME ignore windows
+ifndef IS_WINDOWS
+
+source=index.rs
+
+all:
+ $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc $(source)
+ cp $(source) $(TMPDIR)
+ cp verify.sh $(TMPDIR)
+ $(call RUN,verify.sh) $(TMPDIR)
+
+else
+all:
+
+endif
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "rustdoc_test"]
+
+// In: Foo
+pub use private::Foo;
+
+mod private {
+ pub struct Foo;
+ impl Foo {
+ // In: test_method
+ pub fn test_method() {}
+ // Out: priv_method
+ fn priv_method() {}
+ }
+
+ pub trait PrivateTrait {
+ // Out: priv_method
+ fn trait_method() {}
+ }
+}
--- /dev/null
+#!/bin/sh
+
+source="$1/index.rs"
+index="$1/doc/search-index.js"
+
+if ! [ -e $index ]
+then
+ echo "Could not find the search index (looked for $index)"
+ exit 1
+fi
+
+ins=$(grep -o 'In: .*' $source | sed 's/In: \(.*\)/\1/g')
+outs=$(grep -o 'Out: .*' $source | sed 's/Out: \(.*\)/\1/g')
+
+for p in $ins
+do
+ if ! grep -q $p $index
+ then
+ echo "'$p' was erroneously excluded from search index."
+ exit 1
+ fi
+done
+
+for p in $outs
+do
+ if grep -q $p $index
+ then
+ echo "'$p' was erroneously included in search index."
+ exit 1
+ fi
+done
+
+exit 0
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:lint_group_plugin_test.rs
+// ignore-stage1
+// ignore-pretty
+
+#![feature(phase)]
+
+#[phase(plugin)]
+extern crate lint_group_plugin_test;
+
+fn lintme() { } //~ WARNING item is named 'lintme'
+fn pleaselintme() { } //~ WARNING item is named 'pleaselintme'
+
+#[allow(lint_me)]
+pub fn main() {
+ fn lintme() { }
+
+ fn pleaselintme() { }
+}
}
}
+macro_rules! while_true {
+ ($e: expr) => {
+ // $e shouldn't be able to interact with this 'x
+ 'x: while 1i + 1 == 2 { $e }
+ }
+}
+
macro_rules! run_once {
($e: expr) => {
// ditto
};
assert_eq!(k, 1i);
+ let l: int = {
+ 'x: for _ in range(0i, 1) {
+ // ditto
+ while_true!(break 'x);
+ i += 1;
+ }
+ i + 1
+ };
+ assert_eq!(l, 1i);
+
let n: int = {
'x: for _ in range(0i, 1) {
// ditto
}
}
+macro_rules! while_x {
+ ($e: expr) => {
+ // ditto
+ 'x: while 1i + 1 == 2 { $e }
+ }
+}
+
pub fn main() {
'x: for _ in range(0i, 1) {
// this 'x should refer to the outer loop, lexically
fail!("break doesn't act hygienically inside infinite loop");
}
+ 'x: while 1i + 1 == 2 {
+ while_x!(break 'x);
+ fail!("break doesn't act hygienically inside infinite while loop");
+ }
+
'x: for _ in range(0i, 1) {
// ditto
run_once!(continue 'x);
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
break 'bar;
}
}
+
+ 'foobar: while 1i + 1 == 2 {
+ loop {
+ break 'foobar;
+ }
+ }
}
// around this problem locally by renaming the constant in the `use`
// form to an uppercase identifier that placates the lint.
-#![deny(non_uppercase_pattern_statics)]
+#![deny(non_uppercase_statics)]
pub static A : int = 97;
}
mod m {
+ #[allow(non_uppercase_statics)]
pub static aha : int = 7;
}
fn visit_char(&mut self) -> bool { true }
fn visit_estr_slice(&mut self) -> bool { true }
- // NOTE: remove after snapshot
- #[cfg(stage0)]
- fn visit_estr_fixed(&mut self,
- _sz: uint, _sz2: uint,
- _align: uint) -> bool { true }
fn visit_box(&mut self, _mtbl: uint, _inner: *const TyDesc) -> bool { true }
fn visit_uniq(&mut self, _mtbl: uint, _inner: *const TyDesc) -> bool { true }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test an edge case in region inference: the lifetime of the borrow
+// of `*x` must be extended to at least 'a.
+
+fn foo<'a,'b>(x: &'a &'b mut int) -> &'a int {
+ let y = &*x; // should be inferred to have type &'a &'b mut int...
+
+ // ...because if we inferred, say, &'x &'b mut int where 'x <= 'a,
+ // this reborrow would be illegal:
+ &**y
+}
+
+pub fn main() {
+ /* Just want to know that it compiles. */
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that the 'static bound on a proc influences lifetimes of
+// region variables contained within (otherwise, region inference will
+// give `x` a very short lifetime).
+
+static i: uint = 3;
+fn foo(_: proc():'static) {}
+fn read(_: uint) { }
+pub fn main() {
+ let x = &i;
+ foo(proc() {
+ read(*x);
+ });
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This is an example where the older inference algorithm failed. The
+// specifics of why it failed are somewhat, but not entirely, tailed
+// to the algorithm. Ultimately the problem is that when computing the
+// mutual supertype of both sides of the `if` it would be faced with a
+// choice of tightening bounds or unifying variables and it took the
+// wrong path. The new algorithm avoids this problem and hence this
+// example typechecks correctly.
+
+enum ScopeChain<'a> {
+ Link(Scope<'a>),
+ End
+}
+
+type Scope<'a> = &'a ScopeChain<'a>;
+
+struct OuterContext;
+
+struct Context<'a> {
+ foo: &'a OuterContext
+}
+
+impl<'a> Context<'a> {
+ fn foo(&mut self, scope: Scope) {
+ let link = if 1i < 2 {
+ let l = Link(scope);
+ self.take_scope(&l);
+ l
+ } else {
+ Link(scope)
+ };
+ self.take_scope(&link);
+ }
+
+ fn take_scope(&mut self, x: Scope) {
+ }
+}
+
+fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-macos #16872 spurious deadlock
+
#![feature(phase)]
#[phase(plugin)]
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+pub fn main() {
+ let mut i = 100i;
+ 'w: while 1i + 1 == 2 {
+ i -= 1;
+ if i == 95 {
+ break 'w;
+ fail!("Should have broken out of loop");
+ }
+ }
+ assert_eq!(i, 95);
+}