1
Fork 0

Auto merge of #40446 - arielb1:rollup, r=alexcrichton

Rollup of 12 pull requests

- Successful merges: #40146, #40299, #40315, #40319, #40344, #40345, #40372, #40373, #40400, #40404, #40419, #40431
- Failed merges:
This commit is contained in:
bors 2017-03-12 02:50:17 +00:00
commit 744e69663e
40 changed files with 527 additions and 232 deletions

View file

@ -46,6 +46,8 @@ matrix:
RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin
SRC=. SRC=.
RUSTC_RETRY_LINKER_ON_SEGFAULT=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1
SCCACHE_ERROR_LOG=/tmp/sccache.log
RUST_LOG=sccache
os: osx os: osx
osx_image: xcode8.2 osx_image: xcode8.2
install: &osx_install_sccache > install: &osx_install_sccache >
@ -56,6 +58,8 @@ matrix:
RUST_CONFIGURE_ARGS=--build=i686-apple-darwin RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
SRC=. SRC=.
RUSTC_RETRY_LINKER_ON_SEGFAULT=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1
SCCACHE_ERROR_LOG=/tmp/sccache.log
RUST_LOG=sccache
os: osx os: osx
osx_image: xcode8.2 osx_image: xcode8.2
install: *osx_install_sccache install: *osx_install_sccache
@ -66,6 +70,8 @@ matrix:
SRC=. SRC=.
DEPLOY=1 DEPLOY=1
RUSTC_RETRY_LINKER_ON_SEGFAULT=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1
SCCACHE_ERROR_LOG=/tmp/sccache.log
RUST_LOG=sccache
os: osx os: osx
osx_image: xcode8.2 osx_image: xcode8.2
install: > install: >
@ -77,6 +83,8 @@ matrix:
SRC=. SRC=.
DEPLOY=1 DEPLOY=1
RUSTC_RETRY_LINKER_ON_SEGFAULT=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1
SCCACHE_ERROR_LOG=/tmp/sccache.log
RUST_LOG=sccache
os: osx os: osx
osx_image: xcode8.2 osx_image: xcode8.2
install: *osx_install_sccache install: *osx_install_sccache
@ -92,6 +100,8 @@ matrix:
SRC=. SRC=.
DEPLOY_ALT=1 DEPLOY_ALT=1
RUSTC_RETRY_LINKER_ON_SEGFAULT=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1
SCCACHE_ERROR_LOG=/tmp/sccache.log
RUST_LOG=sccache
os: osx os: osx
osx_image: xcode8.2 osx_image: xcode8.2
install: *osx_install_sccache install: *osx_install_sccache
@ -133,6 +143,7 @@ after_failure:
df -h; df -h;
du . | sort -nr | head -n100 du . | sort -nr | head -n100
- cat obj/tmp/sccache.log - cat obj/tmp/sccache.log
- cat /tmp/sccache.log
# Save tagged docker images we created and load them if they're available # Save tagged docker images we created and load them if they're available
before_cache: before_cache:

View file

@ -130,12 +130,19 @@ install:
- set PATH=%PATH%;%CD%\handle - set PATH=%PATH%;%CD%\handle
- handle.exe -accepteula -help - handle.exe -accepteula -help
# Attempt to debug sccache failures
- set RUST_LOG=sccache
- set SCCACHE_ERROR_LOG=%CD%/sccache.log
test_script: test_script:
- appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init' - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init'
- set SRC=. - set SRC=.
- set NO_CCACHE=1 - set NO_CCACHE=1
- sh src/ci/run.sh - sh src/ci/run.sh
on_failure:
- cat %CD%/sccache.log
cache: cache:
- "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
- "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"

View file

@ -529,6 +529,26 @@ pub trait Debug {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub trait Display { pub trait Display {
/// Formats the value using the given formatter. /// Formats the value using the given formatter.
///
/// # Examples
///
/// ```
/// use std::fmt;
///
/// struct Position {
/// longitude: f32,
/// latitude: f32,
/// }
///
/// impl fmt::Display for Position {
/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// write!(f, "({}, {})", self.longitude, self.latitude)
/// }
/// }
///
/// assert_eq!("(1.987, 2.983)".to_owned(),
/// format!("{}", Position { longitude: 1.987, latitude: 2.983, }));
/// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
fn fmt(&self, f: &mut Formatter) -> Result; fn fmt(&self, f: &mut Formatter) -> Result;
} }
@ -930,7 +950,6 @@ pub fn write(output: &mut Write, args: Arguments) -> Result {
} }
impl<'a> Formatter<'a> { impl<'a> Formatter<'a> {
// First up is the collection of functions used to execute a format string // First up is the collection of functions used to execute a format string
// at runtime. This consumes all of the compile-time statics generated by // at runtime. This consumes all of the compile-time statics generated by
// the format! syntax extension. // the format! syntax extension.

View file

@ -152,7 +152,7 @@ course, it depends on the program.
The main case which fails today that I would like to support is: The main case which fails today that I would like to support is:
```text ```rust
fn foo<T>(x: T, y: T) { ... } fn foo<T>(x: T, y: T) { ... }
fn bar() { fn bar() {
@ -168,6 +168,8 @@ because the type variable `T` is merged with the type variable for
`X`, and thus inherits its UB/LB of `@mut int`. This leaves no `X`, and thus inherits its UB/LB of `@mut int`. This leaves no
flexibility for `T` to later adjust to accommodate `@int`. flexibility for `T` to later adjust to accommodate `@int`.
Note: `@` and `@mut` are replaced with `Rc<T>` and `Rc<RefCell<T>>` in current Rust.
### What to do when not all bounds are present ### What to do when not all bounds are present
In the prior discussion we assumed that A.ub was not top and B.lb was In the prior discussion we assumed that A.ub was not top and B.lb was

View file

@ -121,17 +121,19 @@ every expression, block, and pattern (patterns are considered to
"execute" by testing the value they are applied to and creating any "execute" by testing the value they are applied to and creating any
relevant bindings). So, for example: relevant bindings). So, for example:
fn foo(x: isize, y: isize) { // -+ ```rust
// +------------+ // | fn foo(x: isize, y: isize) { // -+
// | +-----+ // | // +------------+ // |
// | +-+ +-+ +-+ // | // | +-----+ // |
// | | | | | | | // | // | +-+ +-+ +-+ // |
// v v v v v v v // | // | | | | | | | // |
let z = x + y; // | // v v v v v v v // |
... // | let z = x + y; // |
} // -+ ... // |
} // -+
fn bar() { ... } fn bar() { ... }
```
In this example, there is a region for the fn body block as a whole, In this example, there is a region for the fn body block as a whole,
and then a subregion for the declaration of the local variable. and then a subregion for the declaration of the local variable.
@ -160,7 +162,9 @@ this, we get a lot of spurious errors around nested calls, in
particular when combined with `&mut` functions. For example, a call particular when combined with `&mut` functions. For example, a call
like this one like this one
self.foo(self.bar()) ```rust
self.foo(self.bar())
```
where both `foo` and `bar` are `&mut self` functions will always yield where both `foo` and `bar` are `&mut self` functions will always yield
an error. an error.
@ -168,20 +172,22 @@ an error.
Here is a more involved example (which is safe) so we can see what's Here is a more involved example (which is safe) so we can see what's
going on: going on:
struct Foo { f: usize, g: usize } ```rust
... struct Foo { f: usize, g: usize }
fn add(p: &mut usize, v: usize) { // ...
*p += v; fn add(p: &mut usize, v: usize) {
} *p += v;
... }
fn inc(p: &mut usize) -> usize { // ...
*p += 1; *p fn inc(p: &mut usize) -> usize {
} *p += 1; *p
fn weird() { }
let mut x: Box<Foo> = box Foo { ... }; fn weird() {
'a: add(&mut (*x).f, let mut x: Box<Foo> = box Foo { /* ... */ };
'b: inc(&mut (*x).f)) // (..) 'a: add(&mut (*x).f,
} 'b: inc(&mut (*x).f)) // (..)
}
```
The important part is the line marked `(..)` which contains a call to The important part is the line marked `(..)` which contains a call to
`add()`. The first argument is a mutable borrow of the field `f`. The `add()`. The first argument is a mutable borrow of the field `f`. The
@ -197,16 +203,18 @@ can see that this error is unnecessary. Let's examine the lifetimes
involved with `'a` in detail. We'll break apart all the steps involved involved with `'a` in detail. We'll break apart all the steps involved
in a call expression: in a call expression:
'a: { ```rust
'a_arg1: let a_temp1: ... = add; 'a: {
'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f; 'a_arg1: let a_temp1: ... = add;
'a_arg3: let a_temp3: usize = { 'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f;
let b_temp1: ... = inc; 'a_arg3: let a_temp3: usize = {
let b_temp2: &'b = &'b mut (*x).f; let b_temp1: ... = inc;
'b_call: b_temp1(b_temp2) let b_temp2: &'b = &'b mut (*x).f;
}; 'b_call: b_temp1(b_temp2)
'a_call: a_temp1(a_temp2, a_temp3) // (**) };
} 'a_call: a_temp1(a_temp2, a_temp3) // (**)
}
```
Here we see that the lifetime `'a` includes a number of substatements. Here we see that the lifetime `'a` includes a number of substatements.
In particular, there is this lifetime I've called `'a_call` that In particular, there is this lifetime I've called `'a_call` that
@ -225,19 +233,21 @@ it will not be *dereferenced* during the evaluation of the second
argument, it can still be *invalidated* by that evaluation. Consider argument, it can still be *invalidated* by that evaluation. Consider
this similar but unsound example: this similar but unsound example:
struct Foo { f: usize, g: usize } ```rust
... struct Foo { f: usize, g: usize }
fn add(p: &mut usize, v: usize) { // ...
*p += v; fn add(p: &mut usize, v: usize) {
} *p += v;
... }
fn consume(x: Box<Foo>) -> usize { // ...
x.f + x.g fn consume(x: Box<Foo>) -> usize {
} x.f + x.g
fn weird() { }
let mut x: Box<Foo> = box Foo { ... }; fn weird() {
'a: add(&mut (*x).f, consume(x)) // (..) let mut x: Box<Foo> = box Foo { ... };
} 'a: add(&mut (*x).f, consume(x)) // (..)
}
```
In this case, the second argument to `add` actually consumes `x`, thus In this case, the second argument to `add` actually consumes `x`, thus
invalidating the first argument. invalidating the first argument.

View file

@ -91,7 +91,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
}; };
if output_template.is_empty() { if output_template.is_empty() {
bug!("empty string provided as RUST_REGION_GRAPH"); panic!("empty string provided as RUST_REGION_GRAPH");
} }
if output_template.contains('%') { if output_template.contains('%') {

View file

@ -806,6 +806,12 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
self.tables = old_tables; self.tables = old_tables;
} }
fn visit_body(&mut self, body: &'tcx hir::Body) {
run_lints!(self, check_body, late_passes, body);
hir_visit::walk_body(self, body);
run_lints!(self, check_body_post, late_passes, body);
}
fn visit_item(&mut self, it: &'tcx hir::Item) { fn visit_item(&mut self, it: &'tcx hir::Item) {
self.with_lint_attrs(&it.attrs, |cx| { self.with_lint_attrs(&it.attrs, |cx| {
run_lints!(cx, check_item, late_passes, it); run_lints!(cx, check_item, late_passes, it);

View file

@ -133,6 +133,8 @@ pub trait LintPass {
// FIXME: eliminate the duplication with `Visitor`. But this also // FIXME: eliminate the duplication with `Visitor`. But this also
// contains a few lint-specific methods with no equivalent in `Visitor`. // contains a few lint-specific methods with no equivalent in `Visitor`.
pub trait LateLintPass<'a, 'tcx>: LintPass { pub trait LateLintPass<'a, 'tcx>: LintPass {
fn check_body(&mut self, _: &LateContext, _: &'tcx hir::Body) { }
fn check_body_post(&mut self, _: &LateContext, _: &'tcx hir::Body) { }
fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { } fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { }
fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { }
fn check_crate_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } fn check_crate_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { }

View file

@ -23,11 +23,17 @@ use super::{
ObjectSafetyViolation, ObjectSafetyViolation,
}; };
use errors::DiagnosticBuilder;
use fmt_macros::{Parser, Piece, Position}; use fmt_macros::{Parser, Piece, Position};
use hir::{intravisit, Local, Pat};
use hir::intravisit::{Visitor, NestedVisitorMap};
use hir::map::NodeExpr;
use hir::def_id::DefId; use hir::def_id::DefId;
use infer::{self, InferCtxt}; use infer::{self, InferCtxt};
use infer::type_variable::TypeVariableOrigin; use infer::type_variable::TypeVariableOrigin;
use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
use std::fmt;
use syntax::ast;
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use ty::error::ExpectedFound; use ty::error::ExpectedFound;
use ty::fast_reject; use ty::fast_reject;
@ -35,12 +41,8 @@ use ty::fold::TypeFolder;
use ty::subst::Subst; use ty::subst::Subst;
use util::nodemap::{FxHashMap, FxHashSet}; use util::nodemap::{FxHashMap, FxHashSet};
use std::fmt;
use syntax::ast;
use hir::{intravisit, Local, Pat};
use hir::intravisit::{Visitor, NestedVisitorMap};
use syntax_pos::{DUMMY_SP, Span}; use syntax_pos::{DUMMY_SP, Span};
use errors::DiagnosticBuilder;
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]
pub struct TraitErrorKey<'tcx> { pub struct TraitErrorKey<'tcx> {
@ -848,15 +850,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
err.span_label(cause.span, &format!("cannot infer type for `{}`", name)); err.span_label(cause.span, &format!("cannot infer type for `{}`", name));
let expr = self.tcx.hir.expect_expr(cause.body_id);
let mut local_visitor = FindLocalByTypeVisitor { let mut local_visitor = FindLocalByTypeVisitor {
infcx: &self, infcx: &self,
target_ty: &ty, target_ty: &ty,
found_pattern: None, found_pattern: None,
}; };
local_visitor.visit_expr(expr); // #40294: cause.body_id can also be a fn declaration.
// Currently, if it's anything other than NodeExpr, we just ignore it
match self.tcx.hir.find(cause.body_id) {
Some(NodeExpr(expr)) => local_visitor.visit_expr(expr),
_ => ()
}
if let Some(pattern) = local_visitor.found_pattern { if let Some(pattern) = local_visitor.found_pattern {
let pattern_span = pattern.span; let pattern_span = pattern.span;

View file

@ -2461,7 +2461,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let new_trait = tcx.mk_dynamic( let new_trait = tcx.mk_dynamic(
ty::Binder(tcx.mk_existential_predicates(iter)), r_b); ty::Binder(tcx.mk_existential_predicates(iter)), r_b);
let InferOk { obligations, .. } = let InferOk { obligations, .. } =
self.infcx.sub_types(false, &obligation.cause, new_trait, target) self.infcx.eq_types(false, &obligation.cause, new_trait, target)
.map_err(|_| Unimplemented)?; .map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations); self.inferred_obligations.extend(obligations);
@ -2520,7 +2520,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// [T; n] -> [T]. // [T; n] -> [T].
(&ty::TyArray(a, _), &ty::TySlice(b)) => { (&ty::TyArray(a, _), &ty::TySlice(b)) => {
let InferOk { obligations, .. } = let InferOk { obligations, .. } =
self.infcx.sub_types(false, &obligation.cause, a, b) self.infcx.eq_types(false, &obligation.cause, a, b)
.map_err(|_| Unimplemented)?; .map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations); self.inferred_obligations.extend(obligations);
} }
@ -2583,7 +2583,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}); });
let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
let InferOk { obligations, .. } = let InferOk { obligations, .. } =
self.infcx.sub_types(false, &obligation.cause, new_struct, target) self.infcx.eq_types(false, &obligation.cause, new_struct, target)
.map_err(|_| Unimplemented)?; .map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations); self.inferred_obligations.extend(obligations);

View file

@ -25,7 +25,7 @@ const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "
const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0", const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
"sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0", "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
"ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0", "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
"sse4a\0", "rdrnd\0", "rdseed\0"]; "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0"];
/// Add `target_feature = "..."` cfgs for a variety of platform /// Add `target_feature = "..."` cfgs for a variety of platform
/// specific features (SSE, NEON etc.). /// specific features (SSE, NEON etc.).

View file

@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
(https://github.com/rust-lang/rust/issues/39283)"); (https://github.com/rust-lang/rust/issues/39283)");
} }
if temp_lifetime.is_some() { if !expr_ty.is_never() && temp_lifetime.is_some() {
this.cfg.push(block, Statement { this.cfg.push(block, Statement {
source_info: source_info, source_info: source_info,
kind: StatementKind::StorageLive(temp.clone()) kind: StatementKind::StorageLive(temp.clone())

View file

@ -395,7 +395,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
} }
} }
None => { None => {
span_bug!(span, "Could not find container for method {}", id); debug!("Could not find container for method {} at {:?}", id, span);
// This is not necessarily a bug, if there was a compilation error, the tables
// we need might not exist.
return None;
} }
}, },
}; };

View file

@ -12,6 +12,7 @@ use astconv::AstConv;
use super::FnCtxt; use super::FnCtxt;
use rustc::infer::InferOk;
use rustc::traits; use rustc::traits;
use rustc::ty::{self, Ty, TraitRef}; use rustc::ty::{self, Ty, TraitRef};
use rustc::ty::{ToPredicate, TypeFoldable}; use rustc::ty::{ToPredicate, TypeFoldable};
@ -149,6 +150,14 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I) pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I)
where I: IntoIterator<Item = &'b hir::Expr> where I: IntoIterator<Item = &'b hir::Expr>
{
let fcx = self.fcx;
fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs));
}
pub fn finalize_as_infer_ok<'b, I>(self, pref: LvaluePreference, exprs: I)
-> InferOk<'tcx, ()>
where I: IntoIterator<Item = &'b hir::Expr>
{ {
let methods: Vec<_> = self.steps let methods: Vec<_> = self.steps
.iter() .iter()
@ -176,8 +185,9 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
} }
} }
for obligation in self.obligations { InferOk {
self.fcx.register_predicate(obligation); value: (),
obligations: self.obligations
} }
} }
} }

View file

@ -64,7 +64,8 @@ use check::FnCtxt;
use rustc::hir; use rustc::hir;
use rustc::hir::def_id::DefId; use rustc::hir::def_id::DefId;
use rustc::infer::{Coercion, InferOk, TypeTrace}; use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace};
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::traits::{self, ObligationCause, ObligationCauseCode};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
use rustc::ty::{self, LvaluePreference, TypeAndMut, use rustc::ty::{self, LvaluePreference, TypeAndMut,
@ -75,9 +76,7 @@ use rustc::ty::relate::RelateResult;
use rustc::ty::subst::Subst; use rustc::ty::subst::Subst;
use syntax::abi; use syntax::abi;
use syntax::feature_gate; use syntax::feature_gate;
use util::common::indent;
use std::cell::RefCell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::ops::Deref; use std::ops::Deref;
@ -85,7 +84,6 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
cause: ObligationCause<'tcx>, cause: ObligationCause<'tcx>,
use_lub: bool, use_lub: bool,
unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
} }
impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> {
@ -95,7 +93,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> {
} }
} }
type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, Adjust<'tcx>)>; type CoerceResult<'tcx> = InferResult<'tcx, Adjustment<'tcx>>;
fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
to_mutbl: hir::Mutability) to_mutbl: hir::Mutability)
@ -108,44 +106,53 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
} }
} }
fn identity<'tcx>() -> Adjust<'tcx> {
Adjust::DerefRef {
autoderefs: 0,
autoref: None,
unsize: false,
}
}
fn success<'tcx>(kind: Adjust<'tcx>,
target: Ty<'tcx>,
obligations: traits::PredicateObligations<'tcx>)
-> CoerceResult<'tcx> {
Ok(InferOk {
value: Adjustment {
kind,
target
},
obligations
})
}
impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self { fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self {
Coerce { Coerce {
fcx: fcx, fcx: fcx,
cause: cause, cause: cause,
use_lub: false, use_lub: false,
unsizing_obligations: RefCell::new(vec![]),
} }
} }
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
self.commit_if_ok(|_| { self.commit_if_ok(|_| {
let trace = TypeTrace::types(&self.cause, false, a, b); let trace = TypeTrace::types(&self.cause, false, a, b);
if self.use_lub { if self.use_lub {
self.lub(false, trace, &a, &b) self.lub(false, trace, &a, &b)
.map(|ok| self.register_infer_ok_obligations(ok))
} else { } else {
self.sub(false, trace, &a, &b) self.sub(false, trace, &a, &b)
.map(|InferOk { value, obligations }| {
self.fcx.register_predicates(obligations);
value
})
} }
}) })
} }
/// Unify two types (using sub or lub) and produce a noop coercion. /// Unify two types (using sub or lub) and produce a specific coercion.
fn unify_and_identity(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, kind: Adjust<'tcx>)
self.unify(&a, &b).and_then(|ty| self.identity(ty)) -> CoerceResult<'tcx> {
} self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| {
success(kind, ty, obligations)
/// Synthesize an identity adjustment. })
fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> {
Ok((ty, Adjust::DerefRef {
autoderefs: 0,
autoref: None,
unsize: false,
}))
} }
fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx>
@ -158,11 +165,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
// Just ignore error types. // Just ignore error types.
if a.references_error() || b.references_error() { if a.references_error() || b.references_error() {
return self.identity(b); return success(identity(), b, vec![]);
} }
if a.is_never() { if a.is_never() {
return Ok((b, Adjust::NeverToAny)); return success(Adjust::NeverToAny, b, vec![]);
} }
// Consider coercing the subtype to a DST // Consider coercing the subtype to a DST
@ -208,7 +215,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
} }
_ => { _ => {
// Otherwise, just use unification rules. // Otherwise, just use unification rules.
self.unify_and_identity(a, b) self.unify_and(a, b, identity())
} }
} }
} }
@ -240,7 +247,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
(r_a, mt_a) (r_a, mt_a)
} }
_ => return self.unify_and_identity(a, b), _ => return self.unify_and(a, b, identity()),
}; };
let span = self.cause.span; let span = self.cause.span;
@ -248,7 +255,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
let mut first_error = None; let mut first_error = None;
let mut r_borrow_var = None; let mut r_borrow_var = None;
let mut autoderef = self.autoderef(span, a); let mut autoderef = self.autoderef(span, a);
let mut success = None; let mut found = None;
for (referent_ty, autoderefs) in autoderef.by_ref() { for (referent_ty, autoderefs) in autoderef.by_ref() {
if autoderefs == 0 { if autoderefs == 0 {
@ -346,8 +353,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
mutbl: mt_b.mutbl, // [1] above mutbl: mt_b.mutbl, // [1] above
}); });
match self.unify(derefd_ty_a, b) { match self.unify(derefd_ty_a, b) {
Ok(ty) => { Ok(ok) => {
success = Some((ty, autoderefs)); found = Some((ok, autoderefs));
break; break;
} }
Err(err) => { Err(err) => {
@ -363,7 +370,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
// (e.g., in example above, the failure from relating `Vec<T>` // (e.g., in example above, the failure from relating `Vec<T>`
// to the target type), since that should be the least // to the target type), since that should be the least
// confusing. // confusing.
let (ty, autoderefs) = match success { let (InferOk { value: ty, mut obligations }, autoderefs) = match found {
Some(d) => d, Some(d) => d,
None => { None => {
let err = first_error.expect("coerce_borrowed_pointer had no error"); let err = first_error.expect("coerce_borrowed_pointer had no error");
@ -372,12 +379,6 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
} }
}; };
// This commits the obligations to the fulfillcx. After this succeeds,
// this snapshot can't be rolled back.
autoderef.finalize(LvaluePreference::from_mutbl(mt_b.mutbl), exprs());
// Now apply the autoref. We have to extract the region out of
// the final ref type we got.
if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 { if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 {
// As a special case, if we would produce `&'a *x`, that's // As a special case, if we would produce `&'a *x`, that's
// a total no-op. We end up with the type `&'a T` just as // a total no-op. We end up with the type `&'a T` just as
@ -391,8 +392,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
// `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`,
// which is a borrow. // which is a borrow.
assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U
return self.identity(ty); return success(identity(), ty, obligations);
} }
// Now apply the autoref. We have to extract the region out of
// the final ref type we got.
let r_borrow = match ty.sty { let r_borrow = match ty.sty {
ty::TyRef(r_borrow, _) => r_borrow, ty::TyRef(r_borrow, _) => r_borrow,
_ => span_bug!(span, "expected a ref type, got {:?}", ty), _ => span_bug!(span, "expected a ref type, got {:?}", ty),
@ -402,11 +406,15 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
ty, ty,
autoderefs, autoderefs,
autoref); autoref);
Ok((ty, Adjust::DerefRef {
let pref = LvaluePreference::from_mutbl(mt_b.mutbl);
obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs()).obligations);
success(Adjust::DerefRef {
autoderefs: autoderefs, autoderefs: autoderefs,
autoref: autoref, autoref: autoref,
unsize: false, unsize: false,
})) }, ty, obligations)
} }
@ -445,18 +453,32 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
} }
_ => (source, None), _ => (source, None),
}; };
let source = source.adjust_for_autoref(self.tcx, reborrow); let coerce_source = source.adjust_for_autoref(self.tcx, reborrow);
let adjust = Adjust::DerefRef {
autoderefs: if reborrow.is_some() { 1 } else { 0 },
autoref: reborrow,
unsize: true,
};
// Setup either a subtyping or a LUB relationship between
// the `CoerceUnsized` target type and the expected type.
// We only have the latter, so we use an inference variable
// for the former and let type inference do the rest.
let origin = TypeVariableOrigin::MiscVariable(self.cause.span);
let coerce_target = self.next_ty_var(origin);
let mut coercion = self.unify_and(coerce_target, target, adjust)?;
let mut selcx = traits::SelectionContext::new(self); let mut selcx = traits::SelectionContext::new(self);
// Use a FIFO queue for this custom fulfillment procedure. // Use a FIFO queue for this custom fulfillment procedure.
let mut queue = VecDeque::new(); let mut queue = VecDeque::new();
let mut leftover_predicates = vec![];
// Create an obligation for `Source: CoerceUnsized<Target>`. // Create an obligation for `Source: CoerceUnsized<Target>`.
let cause = ObligationCause::misc(self.cause.span, self.body_id); let cause = ObligationCause::misc(self.cause.span, self.body_id);
queue.push_back(self.tcx queue.push_back(self.tcx
.predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target])); .predicate_for_trait_def(cause, coerce_unsized_did, 0,
coerce_source, &[coerce_target]));
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@ -467,7 +489,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
let trait_ref = match obligation.predicate { let trait_ref = match obligation.predicate {
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(), ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(),
_ => { _ => {
leftover_predicates.push(obligation); coercion.obligations.push(obligation);
continue; continue;
} }
}; };
@ -495,33 +517,26 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
} }
} }
*self.unsizing_obligations.borrow_mut() = leftover_predicates; Ok(coercion)
let adjustment = Adjust::DerefRef {
autoderefs: if reborrow.is_some() { 1 } else { 0 },
autoref: reborrow,
unsize: true,
};
debug!("Success, coerced with {:?}", adjustment);
Ok((target, adjustment))
} }
fn coerce_from_safe_fn(&self, fn coerce_from_safe_fn(&self,
a: Ty<'tcx>, a: Ty<'tcx>,
fn_ty_a: ty::PolyFnSig<'tcx>, fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>) b: Ty<'tcx>,
to_unsafe: Adjust<'tcx>,
normal: Adjust<'tcx>)
-> CoerceResult<'tcx> { -> CoerceResult<'tcx> {
if let ty::TyFnPtr(fn_ty_b) = b.sty { if let ty::TyFnPtr(fn_ty_b) = b.sty {
match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) { match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) {
(hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
return self.unify_and_identity(unsafe_a, b) return self.unify_and(unsafe_a, b, to_unsafe);
.map(|(ty, _)| (ty, Adjust::UnsafeFnPointer));
} }
_ => {} _ => {}
} }
} }
self.unify_and_identity(a, b) self.unify_and(a, b, normal)
} }
fn coerce_from_fn_pointer(&self, fn coerce_from_fn_pointer(&self,
@ -536,7 +551,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
let b = self.shallow_resolve(b); let b = self.shallow_resolve(b);
debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
self.coerce_from_safe_fn(a, fn_ty_a, b) self.coerce_from_safe_fn(a, fn_ty_a, b,
Adjust::UnsafeFnPointer, identity())
} }
fn coerce_from_fn_item(&self, fn coerce_from_fn_item(&self,
@ -554,10 +570,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
match b.sty { match b.sty {
ty::TyFnPtr(_) => { ty::TyFnPtr(_) => {
let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a); let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b) self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b,
.map(|(ty, _)| (ty, Adjust::ReifyFnPointer)) Adjust::ReifyFnPointer, Adjust::ReifyFnPointer)
} }
_ => self.unify_and_identity(a, b), _ => self.unify_and(a, b, identity()),
} }
} }
@ -582,7 +598,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
self.cause.span, self.cause.span,
feature_gate::GateIssue::Language, feature_gate::GateIssue::Language,
feature_gate::CLOSURE_TO_FN_COERCION); feature_gate::CLOSURE_TO_FN_COERCION);
return self.unify_and_identity(a, b); return self.unify_and(a, b, identity());
} }
// We coerce the closure, which has fn type // We coerce the closure, which has fn type
// `extern "rust-call" fn((arg0,arg1,...)) -> _` // `extern "rust-call" fn((arg0,arg1,...)) -> _`
@ -607,10 +623,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
let pointer_ty = self.tcx.mk_fn_ptr(converted_sig); let pointer_ty = self.tcx.mk_fn_ptr(converted_sig);
debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})",
a, b, pointer_ty); a, b, pointer_ty);
self.unify_and_identity(pointer_ty, b) self.unify_and(pointer_ty, b, Adjust::ClosureFnPointer)
.map(|(ty, _)| (ty, Adjust::ClosureFnPointer))
} }
_ => self.unify_and_identity(a, b), _ => self.unify_and(a, b, identity()),
} }
} }
@ -625,7 +640,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
ty::TyRef(_, mt) => (true, mt), ty::TyRef(_, mt) => (true, mt),
ty::TyRawPtr(mt) => (false, mt), ty::TyRawPtr(mt) => (false, mt),
_ => { _ => {
return self.unify_and_identity(a, b); return self.unify_and(a, b, identity());
} }
}; };
@ -634,52 +649,24 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
mutbl: mutbl_b, mutbl: mutbl_b,
ty: mt_a.ty, ty: mt_a.ty,
}); });
let (ty, noop) = self.unify_and_identity(a_unsafe, b)?;
coerce_mutbls(mt_a.mutbl, mutbl_b)?; coerce_mutbls(mt_a.mutbl, mutbl_b)?;
// Although references and unsafe ptrs have the same // Although references and unsafe ptrs have the same
// representation, we still register an Adjust::DerefRef so that // representation, we still register an Adjust::DerefRef so that
// regionck knows that the region for `a` must be valid here. // regionck knows that the region for `a` must be valid here.
Ok((ty, self.unify_and(a_unsafe, b, if is_ref {
if is_ref { Adjust::DerefRef {
Adjust::DerefRef { autoderefs: 1,
autoderefs: 1, autoref: Some(AutoBorrow::RawPtr(mutbl_b)),
autoref: Some(AutoBorrow::RawPtr(mutbl_b)), unsize: false,
unsize: false, }
} } else if mt_a.mutbl != mutbl_b {
} else if mt_a.mutbl != mutbl_b { Adjust::MutToConstPointer
Adjust::MutToConstPointer } else {
} else { identity()
noop })
}))
} }
} }
fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>,
exprs: &E,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> RelateResult<'tcx, Adjustment<'tcx>>
where E: Fn() -> I,
I: IntoIterator<Item = &'b hir::Expr>
{
let (ty, adjust) = indent(|| coerce.coerce(exprs, a, b))?;
let fcx = coerce.fcx;
if let Adjust::DerefRef { unsize: true, .. } = adjust {
let mut obligations = coerce.unsizing_obligations.borrow_mut();
for obligation in obligations.drain(..) {
fcx.register_predicate(obligation);
}
}
Ok(Adjustment {
kind: adjust,
target: ty
})
}
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// Attempt to coerce an expression to a type, and return the /// Attempt to coerce an expression to a type, and return the
/// adjusted type of the expression, if successful. /// adjusted type of the expression, if successful.
@ -694,9 +681,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
let mut coerce = Coerce::new(self, cause); let coerce = Coerce::new(self, cause);
self.commit_if_ok(|_| { self.commit_if_ok(|_| {
let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?; let ok = coerce.coerce(&|| Some(expr), source, target)?;
let adjustment = self.register_infer_ok_obligations(ok);
if !adjustment.is_identity() { if !adjustment.is_identity() {
debug!("Success, coerced with {:?}", adjustment); debug!("Success, coerced with {:?}", adjustment);
match self.tables.borrow().adjustments.get(&expr.id) { match self.tables.borrow().adjustments.get(&expr.id) {
@ -773,9 +761,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// but only if the new expression has no coercion already applied to it. // but only if the new expression has no coercion already applied to it.
let mut first_error = None; let mut first_error = None;
if !self.tables.borrow().adjustments.contains_key(&new.id) { if !self.tables.borrow().adjustments.contains_key(&new.id) {
let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty)); let result = self.commit_if_ok(|_| coerce.coerce(&|| Some(new), new_ty, prev_ty));
match result { match result {
Ok(adjustment) => { Ok(ok) => {
let adjustment = self.register_infer_ok_obligations(ok);
if !adjustment.is_identity() { if !adjustment.is_identity() {
self.write_adjustment(new.id, adjustment); self.write_adjustment(new.id, adjustment);
} }
@ -816,7 +805,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} }
} }
match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { match self.commit_if_ok(|_| coerce.coerce(&exprs, prev_ty, new_ty)) {
Err(_) => { Err(_) => {
// Avoid giving strange errors on failed attempts. // Avoid giving strange errors on failed attempts.
if let Some(e) = first_error { if let Some(e) = first_error {
@ -828,7 +817,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}) })
} }
} }
Ok(adjustment) => { Ok(ok) => {
let adjustment = self.register_infer_ok_obligations(ok);
if !adjustment.is_identity() { if !adjustment.is_identity() {
let mut tables = self.tables.borrow_mut(); let mut tables = self.tables.borrow_mut();
for expr in exprs() { for expr in exprs() {

View file

@ -442,7 +442,7 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
/// Used when rendering a `ResolvedPath` structure. This invokes the `path` /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
/// rendering function with the necessary arguments for linking to a local path. /// rendering function with the necessary arguments for linking to a local path.
fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
print_all: bool, use_absolute: bool) -> fmt::Result { print_all: bool, use_absolute: bool, is_not_debug: bool) -> fmt::Result {
let last = path.segments.last().unwrap(); let last = path.segments.last().unwrap();
let rel_root = match &*path.segments[0].name { let rel_root = match &*path.segments[0].name {
"self" => Some("./".to_string()), "self" => Some("./".to_string()),
@ -459,10 +459,14 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
} else { } else {
root.push_str(&seg.name); root.push_str(&seg.name);
root.push_str("/"); root.push_str("/");
write!(w, "<a class=\"mod\" if is_not_debug {
href=\"{}index.html\">{}</a>::", write!(w, "<a class=\"mod\"
root, href=\"{}index.html\">{}</a>::",
seg.name)?; root,
seg.name)?;
} else {
write!(w, "{}::", seg.name)?;
}
} }
} }
} }
@ -474,19 +478,37 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
} }
} }
if w.alternate() { if w.alternate() {
write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?; if is_not_debug {
} else { write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?;
let path = if use_absolute {
match href(did) {
Some((_, _, fqp)) => format!("{}::{}",
fqp[..fqp.len()-1].join("::"),
HRef::new(did, fqp.last().unwrap())),
None => format!("{}", HRef::new(did, &last.name)),
}
} else { } else {
format!("{}", HRef::new(did, &last.name)) write!(w, "{:?}{:?}", HRef::new(did, &last.name), last.params)?;
}; }
write!(w, "{}{}", path, last.params)?; } else {
if is_not_debug {
let path = if use_absolute {
match href(did) {
Some((_, _, fqp)) => format!("{}::{}",
fqp[..fqp.len()-1].join("::"),
HRef::new(did, fqp.last().unwrap())),
None => format!("{}", HRef::new(did, &last.name)),
}
} else {
format!("{}", HRef::new(did, &last.name))
};
write!(w, "{}{}", path, last.params)?;
} else {
let path = if use_absolute {
match href(did) {
Some((_, _, fqp)) => format!("{:?}::{:?}",
fqp[..fqp.len()-1].join("::"),
HRef::new(did, fqp.last().unwrap())),
None => format!("{:?}", HRef::new(did, &last.name)),
}
} else {
format!("{:?}", HRef::new(did, &last.name))
};
write!(w, "{}{:?}", path, last.params)?;
}
} }
Ok(()) Ok(())
} }
@ -570,6 +592,12 @@ impl<'a> fmt::Display for HRef<'a> {
} }
} }
impl<'a> fmt::Debug for HRef<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.text)
}
}
fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool, fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool,
is_not_debug: bool) -> fmt::Result { is_not_debug: bool) -> fmt::Result {
match *t { match *t {
@ -578,7 +606,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool,
} }
clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => { clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
// Paths like T::Output and Self::Output should be rendered with all segments // Paths like T::Output and Self::Output should be rendered with all segments
resolved_path(f, did, path, is_generic, use_absolute)?; resolved_path(f, did, path, is_generic, use_absolute, is_not_debug)?;
tybounds(f, typarams) tybounds(f, typarams)
} }
clean::Infer => write!(f, "_"), clean::Infer => write!(f, "_"),
@ -767,7 +795,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool,
write!(f, "{}::", self_type)?; write!(f, "{}::", self_type)?;
} }
let path = clean::Path::singleton(name.clone()); let path = clean::Path::singleton(name.clone());
resolved_path(f, did, &path, true, use_absolute)?; resolved_path(f, did, &path, true, use_absolute, is_not_debug)?;
// FIXME: `typarams` are not rendered, and this seems bad? // FIXME: `typarams` are not rendered, and this seems bad?
drop(typarams); drop(typarams);
@ -1051,7 +1079,7 @@ impl fmt::Display for clean::Import {
impl fmt::Display for clean::ImportSource { impl fmt::Display for clean::ImportSource {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.did { match self.did {
Some(did) => resolved_path(f, did, &self.path, true, false), Some(did) => resolved_path(f, did, &self.path, true, false, true),
_ => { _ => {
for (i, seg) in self.path.segments.iter().enumerate() { for (i, seg) in self.path.segments.iter().enumerate() {
if i > 0 { if i > 0 {

View file

@ -0,0 +1,41 @@
// Copyright 2017 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 prove_static<T: 'static + ?Sized>(_: &'static T) {}
fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T {
let mut out = [x];
//~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements
{
let slice: &mut [_] = &mut out;
slice[0] = y;
}
out[0]
}
struct Struct<T, U: ?Sized> {
head: T,
_tail: U
}
fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T {
let mut out = Struct { head: x, _tail: [()] };
//~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements
{
let dst: &mut Struct<_, [()]> = &mut out;
dst.head = y;
}
out.head
}
fn main() {
prove_static(lifetime_transmute_slice("", &String::from("foo")));
prove_static(lifetime_transmute_struct("", &String::from("bar")));
}

View file

@ -0,0 +1,30 @@
// Copyright 2017 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 save_ref<'a>(refr: &'a i32, to: &mut [&'a i32]) {
for val in &mut *to {
*val = refr;
}
}
fn main() {
let ref init = 0i32;
let ref mut refr = 1i32;
let mut out = [init];
save_ref(&*refr, &mut out);
// This shouldn't be allowed as `refr` is borrowed
*refr = 3; //~ ERROR cannot assign to `*refr` because it is borrowed
// Prints 3?!
println!("{:?}", out[0]);
}

View file

@ -79,7 +79,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait {
// which fails to type check. // which fails to type check.
ss ss
//~^ ERROR lifetime bound not satisfied //~^ ERROR cannot infer
//~| ERROR cannot infer //~| ERROR cannot infer
} }

View file

@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box<SomeTrait> {
// `Box<SomeTrait>` defaults to a `'static` bound, so this return // `Box<SomeTrait>` defaults to a `'static` bound, so this return
// is illegal. // is illegal.
ss.r //~ ERROR lifetime bound not satisfied ss.r //~ ERROR cannot infer an appropriate lifetime
} }
fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) { fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box<SomeTrait>) {
fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) { fn store1<'b>(ss: &mut SomeStruct, b: Box<SomeTrait+'b>) {
// Here we override the lifetimes explicitly, and so naturally we get an error. // Here we override the lifetimes explicitly, and so naturally we get an error.
ss.r = b; //~ ERROR lifetime bound not satisfied ss.r = b; //~ ERROR cannot infer an appropriate lifetime
} }
fn main() { fn main() {

View file

@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'b> {
fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<SomeTrait+'c> {
// A outlives 'a AND 'b...but not 'c. // A outlives 'a AND 'b...but not 'c.
box v as Box<SomeTrait+'a> //~ ERROR lifetime bound not satisfied box v as Box<SomeTrait+'a> //~ ERROR cannot infer an appropriate lifetime
} }
fn main() { fn main() {

View file

@ -16,7 +16,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box<FnMut()->(isize) + 'a> {
fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> { fn static_proc(x: &isize) -> Box<FnMut()->(isize) + 'static> {
// This is illegal, because the region bound on `proc` is 'static. // This is illegal, because the region bound on `proc` is 'static.
Box::new(move|| { *x }) //~ ERROR does not fulfill the required lifetime Box::new(move|| { *x }) //~ ERROR cannot infer an appropriate lifetime
} }
fn main() { } fn main() { }

View file

@ -22,8 +22,8 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) {
fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy {
// Without knowing 'a:'b, we can't coerce // Without knowing 'a:'b, we can't coerce
x //~ ERROR lifetime bound not satisfied x //~ ERROR cannot infer an appropriate lifetime
//~^ ERROR cannot infer //~^ ERROR cannot infer an appropriate lifetime
} }
struct Wrapper<T>(T); struct Wrapper<T>(T);

View file

@ -21,7 +21,7 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
-> Box<Get<&'min i32>> -> Box<Get<&'min i32>>
where 'max : 'min where 'max : 'min
{ {
v //~ ERROR mismatched types v //~ ERROR cannot infer an appropriate lifetime
} }
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>) fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
@ -29,7 +29,7 @@ fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
where 'max : 'min where 'max : 'min
{ {
// Previously OK: // Previously OK:
v //~ ERROR mismatched types v //~ ERROR cannot infer an appropriate lifetime
} }
fn main() { } fn main() { }

View file

@ -22,14 +22,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
where 'max : 'min where 'max : 'min
{ {
// Previously OK, now an error as traits are invariant. // Previously OK, now an error as traits are invariant.
v //~ ERROR mismatched types v //~ ERROR cannot infer an appropriate lifetime
} }
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>) fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
-> Box<Get<&'max i32>> -> Box<Get<&'max i32>>
where 'max : 'min where 'max : 'min
{ {
v //~ ERROR mismatched types v //~ ERROR cannot infer an appropriate lifetime
} }
fn main() { } fn main() { }

View file

@ -18,14 +18,14 @@ fn get_min_from_max<'min, 'max>(v: Box<Get<&'max i32>>)
-> Box<Get<&'min i32>> -> Box<Get<&'min i32>>
where 'max : 'min where 'max : 'min
{ {
v //~ ERROR mismatched types v //~ ERROR cannot infer an appropriate lifetime
} }
fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>) fn get_max_from_min<'min, 'max, G>(v: Box<Get<&'min i32>>)
-> Box<Get<&'max i32>> -> Box<Get<&'max i32>>
where 'max : 'min where 'max : 'min
{ {
v //~ ERROR mismatched types v //~ ERROR cannot infer an appropriate lifetime
} }
fn main() { } fn main() { }

View file

@ -15,31 +15,38 @@
// === GDB TESTS =================================================================================== // === GDB TESTS ===================================================================================
// gdb-command:print 'c_style_enum::SINGLE_VARIANT' // gdbg-command:print 'c_style_enum::SINGLE_VARIANT'
// gdbr-command:print c_style_enum::SINGLE_VARIANT
// gdbg-check:$1 = TheOnlyVariant // gdbg-check:$1 = TheOnlyVariant
// gdbr-check:$1 = c_style_enum::SingleVariant::TheOnlyVariant // gdbr-check:$1 = c_style_enum::SingleVariant::TheOnlyVariant
// gdb-command:print 'c_style_enum::AUTO_ONE' // gdbg-command:print 'c_style_enum::AUTO_ONE'
// gdbr-command:print c_style_enum::AUTO_ONE
// gdbg-check:$2 = One // gdbg-check:$2 = One
// gdbr-check:$2 = c_style_enum::AutoDiscriminant::One // gdbr-check:$2 = c_style_enum::AutoDiscriminant::One
// gdb-command:print 'c_style_enum::AUTO_TWO' // gdbg-command:print 'c_style_enum::AUTO_TWO'
// gdbr-command:print c_style_enum::AUTO_TWO
// gdbg-check:$3 = One // gdbg-check:$3 = One
// gdbr-check:$3 = c_style_enum::AutoDiscriminant::One // gdbr-check:$3 = c_style_enum::AutoDiscriminant::One
// gdb-command:print 'c_style_enum::AUTO_THREE' // gdbg-command:print 'c_style_enum::AUTO_THREE'
// gdbr-command:print c_style_enum::AUTO_THREE
// gdbg-check:$4 = One // gdbg-check:$4 = One
// gdbr-check:$4 = c_style_enum::AutoDiscriminant::One // gdbr-check:$4 = c_style_enum::AutoDiscriminant::One
// gdb-command:print 'c_style_enum::MANUAL_ONE' // gdbg-command:print 'c_style_enum::MANUAL_ONE'
// gdbr-command:print c_style_enum::MANUAL_ONE
// gdbg-check:$5 = OneHundred // gdbg-check:$5 = OneHundred
// gdbr-check:$5 = c_style_enum::ManualDiscriminant::OneHundred // gdbr-check:$5 = c_style_enum::ManualDiscriminant::OneHundred
// gdb-command:print 'c_style_enum::MANUAL_TWO' // gdbg-command:print 'c_style_enum::MANUAL_TWO'
// gdbr-command:print c_style_enum::MANUAL_TWO
// gdbg-check:$6 = OneHundred // gdbg-check:$6 = OneHundred
// gdbr-check:$6 = c_style_enum::ManualDiscriminant::OneHundred // gdbr-check:$6 = c_style_enum::ManualDiscriminant::OneHundred
// gdb-command:print 'c_style_enum::MANUAL_THREE' // gdbg-command:print 'c_style_enum::MANUAL_THREE'
// gdbr-command:print c_style_enum::MANUAL_THREE
// gdbg-check:$7 = OneHundred // gdbg-check:$7 = OneHundred
// gdbr-check:$7 = c_style_enum::ManualDiscriminant::OneHundred // gdbr-check:$7 = c_style_enum::ManualDiscriminant::OneHundred

View file

@ -15,10 +15,14 @@
// Make sure functions have proper names // Make sure functions have proper names
// gdb-command:info functions // gdb-command:info functions
// gdb-check:[...]void[...]main([...]); // gdbg-check:[...]void[...]main([...]);
// gdb-check:[...]void[...]some_function([...]); // gdbr-check:fn limited_debuginfo::main();
// gdb-check:[...]void[...]some_other_function([...]); // gdbg-check:[...]void[...]some_function([...]);
// gdb-check:[...]void[...]zzz([...]); // gdbr-check:fn limited_debuginfo::some_function();
// gdbg-check:[...]void[...]some_other_function([...]);
// gdbr-check:fn limited_debuginfo::some_other_function();
// gdbg-check:[...]void[...]zzz([...]);
// gdbr-check:fn limited_debuginfo::zzz();
// gdb-command:run // gdb-command:run

View file

@ -14,9 +14,6 @@
// === GDB TESTS =================================================================================== // === GDB TESTS ===================================================================================
// there's no frame yet for gdb to reliably detect the language, set it explicitly
// gdbr-command:set language rust
// gdbg-command:print 'simple_struct::NO_PADDING_16' // gdbg-command:print 'simple_struct::NO_PADDING_16'
// gdbr-command:print simple_struct::NO_PADDING_16 // gdbr-command:print simple_struct::NO_PADDING_16
// gdbg-check:$1 = {x = 1000, y = -1001} // gdbg-check:$1 = {x = 1000, y = -1001}

View file

@ -14,9 +14,6 @@
// === GDB TESTS =================================================================================== // === GDB TESTS ===================================================================================
// there's no frame yet for gdb to reliably detect the language, set it explicitly
// gdbr-command:set language rust
// gdbg-command:print/d 'simple_tuple::NO_PADDING_8' // gdbg-command:print/d 'simple_tuple::NO_PADDING_8'
// gdbr-command:print simple_tuple::NO_PADDING_8 // gdbr-command:print simple_tuple::NO_PADDING_8
// gdbg-check:$1 = {__0 = -50, __1 = 50} // gdbg-check:$1 = {__0 = -50, __1 = 50}

View file

@ -35,7 +35,6 @@ fn main() {
// } // }
// //
// bb2: { // bb2: {
// StorageLive(_6);
// _0 = (); // _0 = ();
// StorageDead(_4); // StorageDead(_4);
// StorageDead(_1); // StorageDead(_1);

View file

@ -8,14 +8,36 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::fmt;
#[repr(packed)] #[repr(packed)]
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone)]
struct Foo { struct Foo {
a: i8, a: i8,
b: i16, b: i16,
c: i8 c: i8
} }
impl PartialEq for Foo {
fn eq(&self, other: &Foo) -> bool {
self.a == other.a && self.b == other.b && self.c == other.c
}
}
impl fmt::Debug for Foo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let a = self.a;
let b = self.b;
let c = self.c;
f.debug_struct("Foo")
.field("a", &a)
.field("b", &b)
.field("c", &c)
.finish()
}
}
#[link(name = "test", kind = "static")] #[link(name = "test", kind = "static")]
extern { extern {
fn foo(f: Foo) -> Foo; fn foo(f: Foo) -> Foo;

View file

@ -0,0 +1,48 @@
// Copyright 2017 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.
// pretty-expanded FIXME #23616
use std::rc::Rc;
fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {}
// The two arguments are a subtype of their LUB, after coercion.
fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) {
lub_short(xs, ys);
}
// The argument coerces to a subtype of the return type.
fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] {
xs
}
// Rc<T> is covariant over T just like &T.
fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> {
xs
}
// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]`
// to a subtype of the LUB of `xs` and `ys` (i.e. `&'b [&'a T]`),
// regardless of the order they appear (in if-else/match/array).
fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) {
let _order1 = [xs, ys];
let _order2 = [ys, xs];
}
// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]`
// needs to be coerced, i.e. the resulting type is not &'b [&'static T], but
// rather the `&'b [&'a T]` LUB.
fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) {
let _order1 = [xs, ys];
let _order2 = [ys, xs];
}
fn main() {}

View file

@ -8,15 +8,34 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::fmt;
use std::mem; use std::mem;
#[repr(packed)] #[repr(packed)]
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone)]
struct Foo { struct Foo {
bar: u8, bar: u8,
baz: u64 baz: u64
} }
impl PartialEq for Foo {
fn eq(&self, other: &Foo) -> bool {
self.bar == other.bar && self.baz == other.baz
}
}
impl fmt::Debug for Foo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let bar = self.bar;
let baz = self.baz;
f.debug_struct("Foo")
.field("bar", &bar)
.field("baz", &baz)
.finish()
}
}
pub fn main() { pub fn main() {
let foos = [Foo { bar: 1, baz: 2 }; 10]; let foos = [Foo { bar: 1, baz: 2 }; 10];

View file

@ -0,0 +1,23 @@
// Copyright 2017 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.
trait Foo: Sized {
fn foo(self);
}
fn foo<'a,'b,T>(x: &'a T, y: &'b T)
where &'a T : Foo,
&'b T : Foo
{
x.foo();
y.foo();
}
fn main() { }

View file

@ -0,0 +1,15 @@
error[E0282]: type annotations needed
--> $DIR/issue-40294.rs:15:1
|
15 | fn foo<'a,'b,T>(x: &'a T, y: &'b T)
| _^ starting here...
16 | | where &'a T : Foo,
17 | | &'b T : Foo
18 | | {
19 | | x.foo();
20 | | y.foo();
21 | | }
| |_^ ...ending here: cannot infer type for `&'a T`
error: aborting due to previous error