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:
commit
744e69663e
40 changed files with 527 additions and 232 deletions
11
.travis.yml
11
.travis.yml
|
@ -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:
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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('%') {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) { }
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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.).
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
41
src/test/compile-fail/issue-40288-2.rs
Normal file
41
src/test/compile-fail/issue-40288-2.rs
Normal 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")));
|
||||||
|
}
|
30
src/test/compile-fail/issue-40288.rs
Normal file
30
src/test/compile-fail/issue-40288.rs
Normal 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]);
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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() { }
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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() { }
|
||||||
|
|
|
@ -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() { }
|
||||||
|
|
|
@ -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() { }
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -35,7 +35,6 @@ fn main() {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// bb2: {
|
// bb2: {
|
||||||
// StorageLive(_6);
|
|
||||||
// _0 = ();
|
// _0 = ();
|
||||||
// StorageDead(_4);
|
// StorageDead(_4);
|
||||||
// StorageDead(_1);
|
// StorageDead(_1);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
48
src/test/run-pass/coerce-unsize-subtype.rs
Normal file
48
src/test/run-pass/coerce-unsize-subtype.rs
Normal 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() {}
|
|
@ -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];
|
||||||
|
|
||||||
|
|
23
src/test/ui/type-check/issue-40294.rs
Normal file
23
src/test/ui/type-check/issue-40294.rs
Normal 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() { }
|
15
src/test/ui/type-check/issue-40294.stderr
Normal file
15
src/test/ui/type-check/issue-40294.stderr
Normal 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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue