mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 10:13:54 +00:00
Auto merge of #48520 - Manishearth:rollup, r=Manishearth
Rollup of 15 pull requests - Successful merges: #47689, #48110, #48197, #48296, #48386, #48392, #48404, #48415, #48441, #48448, #48452, #48481, #48490, #48499, #48503 - Failed merges:
This commit is contained in:
commit
026339e42b
@ -313,7 +313,7 @@ impl Step for TestHelpers {
|
|||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
fn should_run(run: ShouldRun) -> ShouldRun {
|
fn should_run(run: ShouldRun) -> ShouldRun {
|
||||||
run.path("src/rt/rust_test_helpers.c")
|
run.path("src/test/auxiliary/rust_test_helpers.c")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_run(run: RunConfig) {
|
fn make_run(run: RunConfig) {
|
||||||
@ -326,7 +326,7 @@ impl Step for TestHelpers {
|
|||||||
let build = builder.build;
|
let build = builder.build;
|
||||||
let target = self.target;
|
let target = self.target;
|
||||||
let dst = build.test_helpers_out(target);
|
let dst = build.test_helpers_out(target);
|
||||||
let src = build.src.join("src/rt/rust_test_helpers.c");
|
let src = build.src.join("src/test/auxiliary/rust_test_helpers.c");
|
||||||
if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
|
if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -353,7 +353,7 @@ impl Step for TestHelpers {
|
|||||||
.opt_level(0)
|
.opt_level(0)
|
||||||
.warnings(false)
|
.warnings(false)
|
||||||
.debug(false)
|
.debug(false)
|
||||||
.file(build.src.join("src/rt/rust_test_helpers.c"))
|
.file(build.src.join("src/test/auxiliary/rust_test_helpers.c"))
|
||||||
.compile("rust_test_helpers");
|
.compile("rust_test_helpers");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit ec5660820dea91df470dab0b9eb26ef798f20889
|
Subproject commit 98921e9de849acdaeaed08cfad6758bb89769b7d
|
@ -359,8 +359,6 @@ impl<T: ?Sized> Box<T> {
|
|||||||
/// Simple usage:
|
/// Simple usage:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(box_leak)]
|
|
||||||
///
|
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let x = Box::new(41);
|
/// let x = Box::new(41);
|
||||||
/// let static_ref: &'static mut usize = Box::leak(x);
|
/// let static_ref: &'static mut usize = Box::leak(x);
|
||||||
@ -372,8 +370,6 @@ impl<T: ?Sized> Box<T> {
|
|||||||
/// Unsized data:
|
/// Unsized data:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(box_leak)]
|
|
||||||
///
|
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let x = vec![1, 2, 3].into_boxed_slice();
|
/// let x = vec![1, 2, 3].into_boxed_slice();
|
||||||
/// let static_ref = Box::leak(x);
|
/// let static_ref = Box::leak(x);
|
||||||
@ -381,8 +377,7 @@ impl<T: ?Sized> Box<T> {
|
|||||||
/// assert_eq!(*static_ref, [4, 2, 3]);
|
/// assert_eq!(*static_ref, [4, 2, 3]);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[unstable(feature = "box_leak", reason = "needs an FCP to stabilize",
|
#[stable(feature = "box_leak", since = "1.26.0")]
|
||||||
issue = "46179")]
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn leak<'a>(b: Box<T>) -> &'a mut T
|
pub fn leak<'a>(b: Box<T>) -> &'a mut T
|
||||||
where
|
where
|
||||||
|
@ -2956,7 +2956,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
|
|
||||||
// Desugar ExprIfLet
|
// Desugar ExprIfLet
|
||||||
// From: `if let <pat> = <sub_expr> <body> [<else_opt>]`
|
// From: `if let <pat> = <sub_expr> <body> [<else_opt>]`
|
||||||
ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => {
|
ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => {
|
||||||
// to:
|
// to:
|
||||||
//
|
//
|
||||||
// match <sub_expr> {
|
// match <sub_expr> {
|
||||||
@ -2970,8 +2970,8 @@ impl<'a> LoweringContext<'a> {
|
|||||||
{
|
{
|
||||||
let body = self.lower_block(body, false);
|
let body = self.lower_block(body, false);
|
||||||
let body_expr = P(self.expr_block(body, ThinVec::new()));
|
let body_expr = P(self.expr_block(body, ThinVec::new()));
|
||||||
let pat = self.lower_pat(pat);
|
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
|
||||||
arms.push(self.arm(hir_vec![pat], body_expr));
|
arms.push(self.arm(pats, body_expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// _ => [<else_opt>|()]
|
// _ => [<else_opt>|()]
|
||||||
@ -3000,7 +3000,7 @@ impl<'a> LoweringContext<'a> {
|
|||||||
|
|
||||||
// Desugar ExprWhileLet
|
// Desugar ExprWhileLet
|
||||||
// From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
|
// From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
|
||||||
ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_label) => {
|
ExprKind::WhileLet(ref pats, ref sub_expr, ref body, opt_label) => {
|
||||||
// to:
|
// to:
|
||||||
//
|
//
|
||||||
// [opt_ident]: loop {
|
// [opt_ident]: loop {
|
||||||
@ -3021,8 +3021,8 @@ impl<'a> LoweringContext<'a> {
|
|||||||
// `<pat> => <body>`
|
// `<pat> => <body>`
|
||||||
let pat_arm = {
|
let pat_arm = {
|
||||||
let body_expr = P(self.expr_block(body, ThinVec::new()));
|
let body_expr = P(self.expr_block(body, ThinVec::new()));
|
||||||
let pat = self.lower_pat(pat);
|
let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
|
||||||
self.arm(hir_vec![pat], body_expr)
|
self.arm(pats, body_expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
// `_ => break`
|
// `_ => break`
|
||||||
|
@ -56,8 +56,19 @@ for ty::subst::Kind<'gcx> {
|
|||||||
fn hash_stable<W: StableHasherResult>(&self,
|
fn hash_stable<W: StableHasherResult>(&self,
|
||||||
hcx: &mut StableHashingContext<'gcx>,
|
hcx: &mut StableHashingContext<'gcx>,
|
||||||
hasher: &mut StableHasher<W>) {
|
hasher: &mut StableHasher<W>) {
|
||||||
self.as_type().hash_stable(hcx, hasher);
|
self.unpack().hash_stable(hcx, hasher);
|
||||||
self.as_region().hash_stable(hcx, hasher);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'gcx> HashStable<StableHashingContext<'gcx>>
|
||||||
|
for ty::subst::UnpackedKind<'gcx> {
|
||||||
|
fn hash_stable<W: StableHasherResult>(&self,
|
||||||
|
hcx: &mut StableHashingContext<'gcx>,
|
||||||
|
hasher: &mut StableHasher<W>) {
|
||||||
|
match self {
|
||||||
|
ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher),
|
||||||
|
ty::subst::UnpackedKind::Type(ty) => ty.hash_stable(hcx, hasher),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ use traits::{self, PredicateObligation};
|
|||||||
use ty::{self, Ty};
|
use ty::{self, Ty};
|
||||||
use ty::fold::{BottomUpFolder, TypeFoldable};
|
use ty::fold::{BottomUpFolder, TypeFoldable};
|
||||||
use ty::outlives::Component;
|
use ty::outlives::Component;
|
||||||
use ty::subst::{Kind, Substs};
|
use ty::subst::{Kind, UnpackedKind, Substs};
|
||||||
use util::nodemap::DefIdMap;
|
use util::nodemap::DefIdMap;
|
||||||
|
|
||||||
pub type AnonTypeMap<'tcx> = DefIdMap<AnonTypeDecl<'tcx>>;
|
pub type AnonTypeMap<'tcx> = DefIdMap<AnonTypeDecl<'tcx>>;
|
||||||
@ -321,7 +321,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||||||
let index = region_def.index as usize;
|
let index = region_def.index as usize;
|
||||||
|
|
||||||
// Get the value supplied for this region from the substs.
|
// Get the value supplied for this region from the substs.
|
||||||
let subst_arg = anon_defn.substs[index].as_region().unwrap();
|
let subst_arg = anon_defn.substs.region_at(index);
|
||||||
|
|
||||||
// Compute the least upper bound of it with the other regions.
|
// Compute the least upper bound of it with the other regions.
|
||||||
debug!("constrain_anon_types: least_region={:?}", least_region);
|
debug!("constrain_anon_types: least_region={:?}", least_region);
|
||||||
@ -466,7 +466,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||||||
// All other regions, we map them appropriately to their adjusted
|
// All other regions, we map them appropriately to their adjusted
|
||||||
// indices, erroring if we find any lifetimes that were not mapped
|
// indices, erroring if we find any lifetimes that were not mapped
|
||||||
// into the new set.
|
// into the new set.
|
||||||
_ => if let Some(r1) = map.get(&Kind::from(r)).and_then(|k| k.as_region()) {
|
_ => if let Some(UnpackedKind::Lifetime(r1)) = map.get(&r.into())
|
||||||
|
.map(|k| k.unpack()) {
|
||||||
r1
|
r1
|
||||||
} else {
|
} else {
|
||||||
// No mapping was found. This means that
|
// No mapping was found. This means that
|
||||||
|
@ -73,7 +73,7 @@ pub enum IntercrateMode {
|
|||||||
/// either identifying an `impl` (e.g., `impl Eq for int`) that
|
/// either identifying an `impl` (e.g., `impl Eq for int`) that
|
||||||
/// provides the required vtable, or else finding a bound that is in
|
/// provides the required vtable, or else finding a bound that is in
|
||||||
/// scope. The eventual result is usually a `Selection` (defined below).
|
/// scope. The eventual result is usually a `Selection` (defined below).
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Obligation<'tcx, T> {
|
pub struct Obligation<'tcx, T> {
|
||||||
pub cause: ObligationCause<'tcx>,
|
pub cause: ObligationCause<'tcx>,
|
||||||
pub param_env: ty::ParamEnv<'tcx>,
|
pub param_env: ty::ParamEnv<'tcx>,
|
||||||
@ -85,7 +85,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
|
|||||||
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
|
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
|
||||||
|
|
||||||
/// Why did we incur this obligation? Used for error reporting.
|
/// Why did we incur this obligation? Used for error reporting.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct ObligationCause<'tcx> {
|
pub struct ObligationCause<'tcx> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ impl<'tcx> ObligationCause<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum ObligationCauseCode<'tcx> {
|
pub enum ObligationCauseCode<'tcx> {
|
||||||
/// Not well classified or should be obvious from span.
|
/// Not well classified or should be obvious from span.
|
||||||
MiscObligation,
|
MiscObligation,
|
||||||
@ -215,7 +215,7 @@ pub enum ObligationCauseCode<'tcx> {
|
|||||||
BlockTailExpression(ast::NodeId),
|
BlockTailExpression(ast::NodeId),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct DerivedObligationCause<'tcx> {
|
pub struct DerivedObligationCause<'tcx> {
|
||||||
/// The trait reference of the parent obligation that led to the
|
/// The trait reference of the parent obligation that led to the
|
||||||
/// current obligation. Note that only trait obligations lead to
|
/// current obligation. Note that only trait obligations lead to
|
||||||
@ -304,7 +304,7 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
|
|||||||
/// ### The type parameter `N`
|
/// ### The type parameter `N`
|
||||||
///
|
///
|
||||||
/// See explanation on `VtableImplData`.
|
/// See explanation on `VtableImplData`.
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
|
||||||
pub enum Vtable<'tcx, N> {
|
pub enum Vtable<'tcx, N> {
|
||||||
/// Vtable identifying a particular impl.
|
/// Vtable identifying a particular impl.
|
||||||
VtableImpl(VtableImplData<'tcx, N>),
|
VtableImpl(VtableImplData<'tcx, N>),
|
||||||
@ -374,13 +374,13 @@ pub struct VtableClosureData<'tcx, N> {
|
|||||||
pub nested: Vec<N>
|
pub nested: Vec<N>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
|
||||||
pub struct VtableAutoImplData<N> {
|
pub struct VtableAutoImplData<N> {
|
||||||
pub trait_def_id: DefId,
|
pub trait_def_id: DefId,
|
||||||
pub nested: Vec<N>
|
pub nested: Vec<N>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
|
||||||
pub struct VtableBuiltinData<N> {
|
pub struct VtableBuiltinData<N> {
|
||||||
pub nested: Vec<N>
|
pub nested: Vec<N>
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ use super::translate_substs;
|
|||||||
use super::Obligation;
|
use super::Obligation;
|
||||||
use super::ObligationCause;
|
use super::ObligationCause;
|
||||||
use super::PredicateObligation;
|
use super::PredicateObligation;
|
||||||
|
use super::Selection;
|
||||||
use super::SelectionContext;
|
use super::SelectionContext;
|
||||||
use super::SelectionError;
|
use super::SelectionError;
|
||||||
use super::VtableClosureData;
|
use super::VtableClosureData;
|
||||||
@ -101,7 +102,7 @@ pub struct MismatchedProjectionTypes<'tcx> {
|
|||||||
pub err: ty::error::TypeError<'tcx>
|
pub err: ty::error::TypeError<'tcx>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
enum ProjectionTyCandidate<'tcx> {
|
enum ProjectionTyCandidate<'tcx> {
|
||||||
// from a where-clause in the env or object type
|
// from a where-clause in the env or object type
|
||||||
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
|
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
|
||||||
@ -110,12 +111,59 @@ enum ProjectionTyCandidate<'tcx> {
|
|||||||
TraitDef(ty::PolyProjectionPredicate<'tcx>),
|
TraitDef(ty::PolyProjectionPredicate<'tcx>),
|
||||||
|
|
||||||
// from a "impl" (or a "pseudo-impl" returned by select)
|
// from a "impl" (or a "pseudo-impl" returned by select)
|
||||||
Select,
|
Select(Selection<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProjectionTyCandidateSet<'tcx> {
|
enum ProjectionTyCandidateSet<'tcx> {
|
||||||
vec: Vec<ProjectionTyCandidate<'tcx>>,
|
None,
|
||||||
ambiguous: bool
|
Single(ProjectionTyCandidate<'tcx>),
|
||||||
|
Ambiguous,
|
||||||
|
Error(SelectionError<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ProjectionTyCandidateSet<'tcx> {
|
||||||
|
fn mark_ambiguous(&mut self) {
|
||||||
|
*self = ProjectionTyCandidateSet::Ambiguous;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_error(&mut self, err: SelectionError<'tcx>) {
|
||||||
|
*self = ProjectionTyCandidateSet::Error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the push was successful, or false if the candidate
|
||||||
|
// was discarded -- this could be because of ambiguity, or because
|
||||||
|
// a higher-priority candidate is already there.
|
||||||
|
fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool {
|
||||||
|
use self::ProjectionTyCandidateSet::*;
|
||||||
|
use self::ProjectionTyCandidate::*;
|
||||||
|
match self {
|
||||||
|
None => {
|
||||||
|
*self = Single(candidate);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Single(current) => {
|
||||||
|
// No duplicates are expected.
|
||||||
|
assert_ne!(current, &candidate);
|
||||||
|
// Prefer where-clauses. As in select, if there are multiple
|
||||||
|
// candidates, we prefer where-clause candidates over impls. This
|
||||||
|
// may seem a bit surprising, since impls are the source of
|
||||||
|
// "truth" in some sense, but in fact some of the impls that SEEM
|
||||||
|
// applicable are not, because of nested obligations. Where
|
||||||
|
// clauses are the safer choice. See the comment on
|
||||||
|
// `select::SelectionCandidate` and #21974 for more details.
|
||||||
|
match (current, candidate) {
|
||||||
|
(ParamEnv(..), ParamEnv(..)) => { *self = Ambiguous; }
|
||||||
|
(ParamEnv(..), _) => {}
|
||||||
|
(_, ParamEnv(..)) => { unreachable!(); }
|
||||||
|
(_, _) => { *self = Ambiguous; }
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Ambiguous | Error(..) => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates constraints of the form:
|
/// Evaluates constraints of the form:
|
||||||
@ -803,11 +851,11 @@ fn project_type<'cx, 'gcx, 'tcx>(
|
|||||||
return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
|
return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut candidates = ProjectionTyCandidateSet {
|
let mut candidates = ProjectionTyCandidateSet::None;
|
||||||
vec: Vec::new(),
|
|
||||||
ambiguous: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// Make sure that the following procedures are kept in order. ParamEnv
|
||||||
|
// needs to be first because it has highest priority, and Select checks
|
||||||
|
// the return value of push_candidate which assumes it's ran at last.
|
||||||
assemble_candidates_from_param_env(selcx,
|
assemble_candidates_from_param_env(selcx,
|
||||||
obligation,
|
obligation,
|
||||||
&obligation_trait_ref,
|
&obligation_trait_ref,
|
||||||
@ -818,67 +866,27 @@ fn project_type<'cx, 'gcx, 'tcx>(
|
|||||||
&obligation_trait_ref,
|
&obligation_trait_ref,
|
||||||
&mut candidates);
|
&mut candidates);
|
||||||
|
|
||||||
if let Err(e) = assemble_candidates_from_impls(selcx,
|
assemble_candidates_from_impls(selcx,
|
||||||
obligation,
|
obligation,
|
||||||
&obligation_trait_ref,
|
&obligation_trait_ref,
|
||||||
&mut candidates) {
|
&mut candidates);
|
||||||
return Err(ProjectionTyError::TraitSelectionError(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("{} candidates, ambiguous={}",
|
match candidates {
|
||||||
candidates.vec.len(),
|
ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress(
|
||||||
candidates.ambiguous);
|
|
||||||
|
|
||||||
// Inherent ambiguity that prevents us from even enumerating the
|
|
||||||
// candidates.
|
|
||||||
if candidates.ambiguous {
|
|
||||||
return Err(ProjectionTyError::TooManyCandidates);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop duplicates.
|
|
||||||
//
|
|
||||||
// Note: `candidates.vec` seems to be on the critical path of the
|
|
||||||
// compiler. Replacing it with an HashSet was also tried, which would
|
|
||||||
// render the following dedup unnecessary. The original comment indicated
|
|
||||||
// that it was 9% slower, but that data is now obsolete and a new
|
|
||||||
// benchmark should be performed.
|
|
||||||
candidates.vec.sort_unstable();
|
|
||||||
candidates.vec.dedup();
|
|
||||||
|
|
||||||
// Prefer where-clauses. As in select, if there are multiple
|
|
||||||
// candidates, we prefer where-clause candidates over impls. This
|
|
||||||
// may seem a bit surprising, since impls are the source of
|
|
||||||
// "truth" in some sense, but in fact some of the impls that SEEM
|
|
||||||
// applicable are not, because of nested obligations. Where
|
|
||||||
// clauses are the safer choice. See the comment on
|
|
||||||
// `select::SelectionCandidate` and #21974 for more details.
|
|
||||||
if candidates.vec.len() > 1 {
|
|
||||||
debug!("retaining param-env candidates only from {:?}", candidates.vec);
|
|
||||||
candidates.vec.retain(|c| match *c {
|
|
||||||
ProjectionTyCandidate::ParamEnv(..) => true,
|
|
||||||
ProjectionTyCandidate::TraitDef(..) |
|
|
||||||
ProjectionTyCandidate::Select => false,
|
|
||||||
});
|
|
||||||
debug!("resulting candidate set: {:?}", candidates.vec);
|
|
||||||
if candidates.vec.len() != 1 {
|
|
||||||
return Err(ProjectionTyError::TooManyCandidates);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(candidates.vec.len() <= 1);
|
|
||||||
|
|
||||||
match candidates.vec.pop() {
|
|
||||||
Some(candidate) => {
|
|
||||||
Ok(ProjectedTy::Progress(
|
|
||||||
confirm_candidate(selcx,
|
confirm_candidate(selcx,
|
||||||
obligation,
|
obligation,
|
||||||
&obligation_trait_ref,
|
&obligation_trait_ref,
|
||||||
candidate)))
|
candidate))),
|
||||||
}
|
ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress(
|
||||||
None => Ok(ProjectedTy::NoProgress(
|
|
||||||
selcx.tcx().mk_projection(
|
selcx.tcx().mk_projection(
|
||||||
obligation.predicate.item_def_id,
|
obligation.predicate.item_def_id,
|
||||||
obligation.predicate.substs)))
|
obligation.predicate.substs))),
|
||||||
|
// Error occurred while trying to processing impls.
|
||||||
|
ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)),
|
||||||
|
// Inherent ambiguity that prevents us from even enumerating the
|
||||||
|
// candidates.
|
||||||
|
ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates),
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -928,7 +936,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>(
|
|||||||
ty::TyInfer(ty::TyVar(_)) => {
|
ty::TyInfer(ty::TyVar(_)) => {
|
||||||
// If the self-type is an inference variable, then it MAY wind up
|
// If the self-type is an inference variable, then it MAY wind up
|
||||||
// being a projected type, so induce an ambiguity.
|
// being a projected type, so induce an ambiguity.
|
||||||
candidate_set.ambiguous = true;
|
candidate_set.mark_ambiguous();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => { return; }
|
_ => { return; }
|
||||||
@ -962,7 +970,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
|
|||||||
debug!("assemble_candidates_from_predicates: predicate={:?}",
|
debug!("assemble_candidates_from_predicates: predicate={:?}",
|
||||||
predicate);
|
predicate);
|
||||||
match predicate {
|
match predicate {
|
||||||
ty::Predicate::Projection(ref data) => {
|
ty::Predicate::Projection(data) => {
|
||||||
let same_def_id =
|
let same_def_id =
|
||||||
data.0.projection_ty.item_def_id == obligation.predicate.item_def_id;
|
data.0.projection_ty.item_def_id == obligation.predicate.item_def_id;
|
||||||
|
|
||||||
@ -985,10 +993,10 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
|
|||||||
data, is_match, same_def_id);
|
data, is_match, same_def_id);
|
||||||
|
|
||||||
if is_match {
|
if is_match {
|
||||||
candidate_set.vec.push(ctor(data.clone()));
|
candidate_set.push_candidate(ctor(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => { }
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -998,37 +1006,36 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
|
|||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||||
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
|
||||||
-> Result<(), SelectionError<'tcx>>
|
|
||||||
{
|
{
|
||||||
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
|
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
|
||||||
// start out by selecting the predicate `T as TraitRef<...>`:
|
// start out by selecting the predicate `T as TraitRef<...>`:
|
||||||
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
||||||
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
|
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
|
||||||
selcx.infcx().probe(|_| {
|
let _ = selcx.infcx().commit_if_ok(|_| {
|
||||||
let vtable = match selcx.select(&trait_obligation) {
|
let vtable = match selcx.select(&trait_obligation) {
|
||||||
Ok(Some(vtable)) => vtable,
|
Ok(Some(vtable)) => vtable,
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
candidate_set.ambiguous = true;
|
candidate_set.mark_ambiguous();
|
||||||
return Ok(());
|
return Err(());
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!("assemble_candidates_from_impls: selection error {:?}",
|
debug!("assemble_candidates_from_impls: selection error {:?}",
|
||||||
e);
|
e);
|
||||||
return Err(e);
|
candidate_set.mark_error(e);
|
||||||
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match vtable {
|
let eligible = match &vtable {
|
||||||
super::VtableClosure(_) |
|
super::VtableClosure(_) |
|
||||||
super::VtableGenerator(_) |
|
super::VtableGenerator(_) |
|
||||||
super::VtableFnPointer(_) |
|
super::VtableFnPointer(_) |
|
||||||
super::VtableObject(_) => {
|
super::VtableObject(_) => {
|
||||||
debug!("assemble_candidates_from_impls: vtable={:?}",
|
debug!("assemble_candidates_from_impls: vtable={:?}",
|
||||||
vtable);
|
vtable);
|
||||||
|
true
|
||||||
candidate_set.vec.push(ProjectionTyCandidate::Select);
|
|
||||||
}
|
}
|
||||||
super::VtableImpl(ref impl_data) => {
|
super::VtableImpl(impl_data) => {
|
||||||
// We have to be careful when projecting out of an
|
// We have to be careful when projecting out of an
|
||||||
// impl because of specialization. If we are not in
|
// impl because of specialization. If we are not in
|
||||||
// trans (i.e., projection mode is not "any"), and the
|
// trans (i.e., projection mode is not "any"), and the
|
||||||
@ -1079,20 +1086,18 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
|
|||||||
// and the obligations is monomorphic, otherwise passes such as
|
// and the obligations is monomorphic, otherwise passes such as
|
||||||
// transmute checking and polymorphic MIR optimizations could
|
// transmute checking and polymorphic MIR optimizations could
|
||||||
// get a result which isn't correct for all monomorphizations.
|
// get a result which isn't correct for all monomorphizations.
|
||||||
let new_candidate = if !is_default {
|
if !is_default {
|
||||||
Some(ProjectionTyCandidate::Select)
|
true
|
||||||
} else if obligation.param_env.reveal == Reveal::All {
|
} else if obligation.param_env.reveal == Reveal::All {
|
||||||
assert!(!poly_trait_ref.needs_infer());
|
assert!(!poly_trait_ref.needs_infer());
|
||||||
if !poly_trait_ref.needs_subst() {
|
if !poly_trait_ref.needs_subst() {
|
||||||
Some(ProjectionTyCandidate::Select)
|
true
|
||||||
} else {
|
} else {
|
||||||
None
|
false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
false
|
||||||
};
|
}
|
||||||
|
|
||||||
candidate_set.vec.extend(new_candidate);
|
|
||||||
}
|
}
|
||||||
super::VtableParam(..) => {
|
super::VtableParam(..) => {
|
||||||
// This case tell us nothing about the value of an
|
// This case tell us nothing about the value of an
|
||||||
@ -1120,6 +1125,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
|
|||||||
// in the compiler: a trait predicate (`T : SomeTrait`) and a
|
// in the compiler: a trait predicate (`T : SomeTrait`) and a
|
||||||
// projection. And the projection where clause is handled
|
// projection. And the projection where clause is handled
|
||||||
// in `assemble_candidates_from_param_env`.
|
// in `assemble_candidates_from_param_env`.
|
||||||
|
false
|
||||||
}
|
}
|
||||||
super::VtableAutoImpl(..) |
|
super::VtableAutoImpl(..) |
|
||||||
super::VtableBuiltin(..) => {
|
super::VtableBuiltin(..) => {
|
||||||
@ -1129,10 +1135,18 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
|
|||||||
"Cannot project an associated type from `{:?}`",
|
"Cannot project an associated type from `{:?}`",
|
||||||
vtable);
|
vtable);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
if eligible {
|
||||||
|
if candidate_set.push_candidate(ProjectionTyCandidate::Select(vtable)) {
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_candidate<'cx, 'gcx, 'tcx>(
|
fn confirm_candidate<'cx, 'gcx, 'tcx>(
|
||||||
@ -1152,8 +1166,8 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>(
|
|||||||
confirm_param_env_candidate(selcx, obligation, poly_projection)
|
confirm_param_env_candidate(selcx, obligation, poly_projection)
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectionTyCandidate::Select => {
|
ProjectionTyCandidate::Select(vtable) => {
|
||||||
confirm_select_candidate(selcx, obligation, obligation_trait_ref)
|
confirm_select_candidate(selcx, obligation, obligation_trait_ref, vtable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1161,21 +1175,10 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>(
|
|||||||
fn confirm_select_candidate<'cx, 'gcx, 'tcx>(
|
fn confirm_select_candidate<'cx, 'gcx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
obligation_trait_ref: &ty::TraitRef<'tcx>)
|
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||||
|
vtable: Selection<'tcx>)
|
||||||
-> Progress<'tcx>
|
-> Progress<'tcx>
|
||||||
{
|
{
|
||||||
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
|
||||||
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
|
|
||||||
let vtable = match selcx.select(&trait_obligation) {
|
|
||||||
Ok(Some(vtable)) => vtable,
|
|
||||||
_ => {
|
|
||||||
span_bug!(
|
|
||||||
obligation.cause.span,
|
|
||||||
"Failed to select `{:?}`",
|
|
||||||
trait_obligation);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match vtable {
|
match vtable {
|
||||||
super::VtableImpl(data) =>
|
super::VtableImpl(data) =>
|
||||||
confirm_impl_candidate(selcx, obligation, data),
|
confirm_impl_candidate(selcx, obligation, data),
|
||||||
|
@ -53,7 +53,7 @@ use std::rc::Rc;
|
|||||||
use syntax::abi::Abi;
|
use syntax::abi::Abi;
|
||||||
use hir;
|
use hir;
|
||||||
use lint;
|
use lint;
|
||||||
use util::nodemap::FxHashMap;
|
use util::nodemap::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
struct InferredObligationsSnapshotVecDelegate<'tcx> {
|
struct InferredObligationsSnapshotVecDelegate<'tcx> {
|
||||||
phantom: PhantomData<&'tcx i32>,
|
phantom: PhantomData<&'tcx i32>,
|
||||||
@ -584,7 +584,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||||||
let trait_ref = &mut trait_pred.trait_ref;
|
let trait_ref = &mut trait_pred.trait_ref;
|
||||||
let unit_substs = trait_ref.substs;
|
let unit_substs = trait_ref.substs;
|
||||||
let mut never_substs = Vec::with_capacity(unit_substs.len());
|
let mut never_substs = Vec::with_capacity(unit_substs.len());
|
||||||
never_substs.push(From::from(tcx.types.never));
|
never_substs.push(tcx.types.never.into());
|
||||||
never_substs.extend(&unit_substs[1..]);
|
never_substs.extend(&unit_substs[1..]);
|
||||||
trait_ref.substs = tcx.intern_substs(&never_substs);
|
trait_ref.substs = tcx.intern_substs(&never_substs);
|
||||||
}
|
}
|
||||||
@ -2997,7 +2997,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||||||
// unsized parameters is equal to the target.
|
// unsized parameters is equal to the target.
|
||||||
let params = substs_a.iter().enumerate().map(|(i, &k)| {
|
let params = substs_a.iter().enumerate().map(|(i, &k)| {
|
||||||
if ty_params.contains(i) {
|
if ty_params.contains(i) {
|
||||||
Kind::from(substs_b.type_at(i))
|
substs_b.type_at(i).into()
|
||||||
} else {
|
} else {
|
||||||
k
|
k
|
||||||
}
|
}
|
||||||
@ -3303,7 +3303,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||||||
// that order.
|
// that order.
|
||||||
let predicates = tcx.predicates_of(def_id);
|
let predicates = tcx.predicates_of(def_id);
|
||||||
assert_eq!(predicates.parent, None);
|
assert_eq!(predicates.parent, None);
|
||||||
let predicates = predicates.predicates.iter().flat_map(|predicate| {
|
let mut predicates: Vec<_> = predicates.predicates.iter().flat_map(|predicate| {
|
||||||
let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth,
|
let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth,
|
||||||
&predicate.subst(tcx, substs));
|
&predicate.subst(tcx, substs));
|
||||||
predicate.obligations.into_iter().chain(
|
predicate.obligations.into_iter().chain(
|
||||||
@ -3314,6 +3314,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
|||||||
predicate: predicate.value
|
predicate: predicate.value
|
||||||
}))
|
}))
|
||||||
}).collect();
|
}).collect();
|
||||||
|
// We are performing deduplication here to avoid exponential blowups
|
||||||
|
// (#38528) from happening, but the real cause of the duplication is
|
||||||
|
// unknown. What we know is that the deduplication avoids exponential
|
||||||
|
// amount of predicates being propogated when processing deeply nested
|
||||||
|
// types.
|
||||||
|
let mut seen = FxHashSet();
|
||||||
|
predicates.retain(|i| seen.insert(i.clone()));
|
||||||
self.infcx().plug_leaks(skol_map, snapshot, predicates)
|
self.infcx().plug_leaks(skol_map, snapshot, predicates)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,10 +355,7 @@ fn fn_once_adapter_instance<'a, 'tcx>(
|
|||||||
let sig = substs.closure_sig(closure_did, tcx);
|
let sig = substs.closure_sig(closure_did, tcx);
|
||||||
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
|
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
|
||||||
assert_eq!(sig.inputs().len(), 1);
|
assert_eq!(sig.inputs().len(), 1);
|
||||||
let substs = tcx.mk_substs([
|
let substs = tcx.mk_substs([Kind::from(self_ty), sig.inputs()[0].into()].iter().cloned());
|
||||||
Kind::from(self_ty),
|
|
||||||
Kind::from(sig.inputs()[0]),
|
|
||||||
].iter().cloned());
|
|
||||||
|
|
||||||
debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
|
debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
|
||||||
Instance { def, substs }
|
Instance { def, substs }
|
||||||
|
@ -39,7 +39,6 @@ use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
|
|||||||
use serialize::{self, Encodable, Encoder};
|
use serialize::{self, Encodable, Encoder};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
@ -498,20 +497,6 @@ impl<'tcx> Hash for TyS<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Ord for TyS<'tcx> {
|
|
||||||
#[inline]
|
|
||||||
fn cmp(&self, other: &TyS<'tcx>) -> Ordering {
|
|
||||||
// (self as *const _).cmp(other as *const _)
|
|
||||||
(self as *const TyS<'tcx>).cmp(&(other as *const TyS<'tcx>))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'tcx> PartialOrd for TyS<'tcx> {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, other: &TyS<'tcx>) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> TyS<'tcx> {
|
impl<'tcx> TyS<'tcx> {
|
||||||
pub fn is_primitive_ty(&self) -> bool {
|
pub fn is_primitive_ty(&self) -> bool {
|
||||||
match self.sty {
|
match self.sty {
|
||||||
@ -581,19 +566,6 @@ impl<T> PartialEq for Slice<T> {
|
|||||||
}
|
}
|
||||||
impl<T> Eq for Slice<T> {}
|
impl<T> Eq for Slice<T> {}
|
||||||
|
|
||||||
impl<T> Ord for Slice<T> {
|
|
||||||
#[inline]
|
|
||||||
fn cmp(&self, other: &Slice<T>) -> Ordering {
|
|
||||||
(&self.0 as *const [T]).cmp(&(&other.0 as *const [T]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T> PartialOrd for Slice<T> {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, other: &Slice<T>) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Hash for Slice<T> {
|
impl<T> Hash for Slice<T> {
|
||||||
fn hash<H: Hasher>(&self, s: &mut H) {
|
fn hash<H: Hasher>(&self, s: &mut H) {
|
||||||
(self.as_ptr(), self.len()).hash(s)
|
(self.as_ptr(), self.len()).hash(s)
|
||||||
@ -1128,7 +1100,7 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder<SubtypePredicate<'tcx>>;
|
|||||||
/// equality between arbitrary types. Processing an instance of
|
/// equality between arbitrary types. Processing an instance of
|
||||||
/// Form #2 eventually yields one of these `ProjectionPredicate`
|
/// Form #2 eventually yields one of these `ProjectionPredicate`
|
||||||
/// instances to normalize the LHS.
|
/// instances to normalize the LHS.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||||
pub struct ProjectionPredicate<'tcx> {
|
pub struct ProjectionPredicate<'tcx> {
|
||||||
pub projection_ty: ProjectionTy<'tcx>,
|
pub projection_ty: ProjectionTy<'tcx>,
|
||||||
pub ty: Ty<'tcx>,
|
pub ty: Ty<'tcx>,
|
||||||
@ -1532,7 +1504,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for AdtDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub enum AdtKind { Struct, Union, Enum }
|
pub enum AdtKind { Struct, Union, Enum }
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use middle::const_val::ConstVal;
|
use middle::const_val::ConstVal;
|
||||||
use traits::Reveal;
|
use traits::Reveal;
|
||||||
use ty::subst::{Kind, Substs};
|
use ty::subst::{UnpackedKind, Substs};
|
||||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
use ty::fold::{TypeVisitor, TypeFolder};
|
use ty::fold::{TypeVisitor, TypeFolder};
|
||||||
use ty::error::{ExpectedFound, TypeError};
|
use ty::error::{ExpectedFound, TypeError};
|
||||||
@ -142,12 +142,14 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
|||||||
|
|
||||||
let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| {
|
let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| {
|
||||||
let variance = variances.map_or(ty::Invariant, |v| v[i]);
|
let variance = variances.map_or(ty::Invariant, |v| v[i]);
|
||||||
if let (Some(a_ty), Some(b_ty)) = (a.as_type(), b.as_type()) {
|
match (a.unpack(), b.unpack()) {
|
||||||
Ok(Kind::from(relation.relate_with_variance(variance, &a_ty, &b_ty)?))
|
(UnpackedKind::Lifetime(a_lt), UnpackedKind::Lifetime(b_lt)) => {
|
||||||
} else if let (Some(a_r), Some(b_r)) = (a.as_region(), b.as_region()) {
|
Ok(relation.relate_with_variance(variance, &a_lt, &b_lt)?.into())
|
||||||
Ok(Kind::from(relation.relate_with_variance(variance, &a_r, &b_r)?))
|
}
|
||||||
} else {
|
(UnpackedKind::Type(a_ty), UnpackedKind::Type(b_ty)) => {
|
||||||
bug!()
|
Ok(relation.relate_with_variance(variance, &a_ty, &b_ty)?.into())
|
||||||
|
}
|
||||||
|
(UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => bug!()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -15,10 +15,9 @@ use hir::def_id::DefId;
|
|||||||
use middle::const_val::ConstVal;
|
use middle::const_val::ConstVal;
|
||||||
use middle::region;
|
use middle::region;
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
use ty::subst::{Substs, Subst};
|
use ty::subst::{Substs, Subst, Kind, UnpackedKind};
|
||||||
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
|
||||||
use ty::{Slice, TyS};
|
use ty::{Slice, TyS};
|
||||||
use ty::subst::Kind;
|
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
@ -297,8 +296,8 @@ impl<'tcx> ClosureSubsts<'tcx> {
|
|||||||
let generics = tcx.generics_of(def_id);
|
let generics = tcx.generics_of(def_id);
|
||||||
let parent_len = generics.parent_count();
|
let parent_len = generics.parent_count();
|
||||||
SplitClosureSubsts {
|
SplitClosureSubsts {
|
||||||
closure_kind_ty: self.substs[parent_len].as_type().expect("CK should be a type"),
|
closure_kind_ty: self.substs.type_at(parent_len),
|
||||||
closure_sig_ty: self.substs[parent_len + 1].as_type().expect("CS should be a type"),
|
closure_sig_ty: self.substs.type_at(parent_len + 1),
|
||||||
upvar_kinds: &self.substs[parent_len + 2..],
|
upvar_kinds: &self.substs[parent_len + 2..],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,7 +307,13 @@ impl<'tcx> ClosureSubsts<'tcx> {
|
|||||||
impl Iterator<Item=Ty<'tcx>> + 'tcx
|
impl Iterator<Item=Ty<'tcx>> + 'tcx
|
||||||
{
|
{
|
||||||
let SplitClosureSubsts { upvar_kinds, .. } = self.split(def_id, tcx);
|
let SplitClosureSubsts { upvar_kinds, .. } = self.split(def_id, tcx);
|
||||||
upvar_kinds.iter().map(|t| t.as_type().expect("upvar should be type"))
|
upvar_kinds.iter().map(|t| {
|
||||||
|
if let UnpackedKind::Type(ty) = t.unpack() {
|
||||||
|
ty
|
||||||
|
} else {
|
||||||
|
bug!("upvar should be type")
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the closure kind for this closure; may return a type
|
/// Returns the closure kind for this closure; may return a type
|
||||||
@ -620,7 +625,7 @@ impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> {
|
|||||||
ty::TraitRef {
|
ty::TraitRef {
|
||||||
def_id: self.def_id,
|
def_id: self.def_id,
|
||||||
substs: tcx.mk_substs(
|
substs: tcx.mk_substs(
|
||||||
iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned()))
|
iter::once(self_ty.into()).chain(self.substs.iter().cloned()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -645,7 +650,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> {
|
|||||||
/// erase, or otherwise "discharge" these bound regions, we change the
|
/// erase, or otherwise "discharge" these bound regions, we change the
|
||||||
/// type from `Binder<T>` to just `T` (see
|
/// type from `Binder<T>` to just `T` (see
|
||||||
/// e.g. `liberate_late_bound_regions`).
|
/// e.g. `liberate_late_bound_regions`).
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||||
pub struct Binder<T>(pub T);
|
pub struct Binder<T>(pub T);
|
||||||
|
|
||||||
impl<T> Binder<T> {
|
impl<T> Binder<T> {
|
||||||
@ -745,7 +750,7 @@ impl<T> Binder<T> {
|
|||||||
|
|
||||||
/// Represents the projection of an associated type. In explicit UFCS
|
/// Represents the projection of an associated type. In explicit UFCS
|
||||||
/// form this would be written `<T as Trait<..>>::N`.
|
/// form this would be written `<T as Trait<..>>::N`.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
|
||||||
pub struct ProjectionTy<'tcx> {
|
pub struct ProjectionTy<'tcx> {
|
||||||
/// The parameters of the associated item.
|
/// The parameters of the associated item.
|
||||||
pub substs: &'tcx Substs<'tcx>,
|
pub substs: &'tcx Substs<'tcx>,
|
||||||
@ -1127,7 +1132,7 @@ impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> {
|
|||||||
projection_ty: ty::ProjectionTy {
|
projection_ty: ty::ProjectionTy {
|
||||||
item_def_id: self.item_def_id,
|
item_def_id: self.item_def_id,
|
||||||
substs: tcx.mk_substs(
|
substs: tcx.mk_substs(
|
||||||
iter::once(Kind::from(self_ty)).chain(self.substs.iter().cloned())),
|
iter::once(self_ty.into()).chain(self.substs.iter().cloned())),
|
||||||
},
|
},
|
||||||
ty: self.ty,
|
ty: self.ty,
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ use serialize::{self, Encodable, Encoder, Decodable, Decoder};
|
|||||||
use syntax_pos::{Span, DUMMY_SP};
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||||
|
|
||||||
|
use core::intrinsics;
|
||||||
use core::nonzero::NonZero;
|
use core::nonzero::NonZero;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
@ -29,7 +30,7 @@ use std::mem;
|
|||||||
/// To reduce memory usage, a `Kind` is a interned pointer,
|
/// To reduce memory usage, a `Kind` is a interned pointer,
|
||||||
/// with the lowest 2 bits being reserved for a tag to
|
/// with the lowest 2 bits being reserved for a tag to
|
||||||
/// indicate the type (`Ty` or `Region`) it points to.
|
/// indicate the type (`Ty` or `Region`) it points to.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Kind<'tcx> {
|
pub struct Kind<'tcx> {
|
||||||
ptr: NonZero<usize>,
|
ptr: NonZero<usize>,
|
||||||
marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)>
|
marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)>
|
||||||
@ -39,15 +40,29 @@ const TAG_MASK: usize = 0b11;
|
|||||||
const TYPE_TAG: usize = 0b00;
|
const TYPE_TAG: usize = 0b00;
|
||||||
const REGION_TAG: usize = 0b01;
|
const REGION_TAG: usize = 0b01;
|
||||||
|
|
||||||
impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
|
pub enum UnpackedKind<'tcx> {
|
||||||
fn from(ty: Ty<'tcx>) -> Kind<'tcx> {
|
Lifetime(ty::Region<'tcx>),
|
||||||
|
Type(Ty<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> UnpackedKind<'tcx> {
|
||||||
|
fn pack(self) -> Kind<'tcx> {
|
||||||
|
let (tag, ptr) = match self {
|
||||||
|
UnpackedKind::Lifetime(lt) => {
|
||||||
|
// Ensure we can use the tag bits.
|
||||||
|
assert_eq!(mem::align_of_val(lt) & TAG_MASK, 0);
|
||||||
|
(REGION_TAG, lt as *const _ as usize)
|
||||||
|
}
|
||||||
|
UnpackedKind::Type(ty) => {
|
||||||
// Ensure we can use the tag bits.
|
// Ensure we can use the tag bits.
|
||||||
assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
|
assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
|
||||||
|
(TYPE_TAG, ty as *const _ as usize)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let ptr = ty as *const _ as usize;
|
|
||||||
Kind {
|
Kind {
|
||||||
ptr: unsafe {
|
ptr: unsafe {
|
||||||
NonZero::new_unchecked(ptr | TYPE_TAG)
|
NonZero::new_unchecked(ptr | tag)
|
||||||
},
|
},
|
||||||
marker: PhantomData
|
marker: PhantomData
|
||||||
}
|
}
|
||||||
@ -56,88 +71,60 @@ impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
|
|||||||
|
|
||||||
impl<'tcx> From<ty::Region<'tcx>> for Kind<'tcx> {
|
impl<'tcx> From<ty::Region<'tcx>> for Kind<'tcx> {
|
||||||
fn from(r: ty::Region<'tcx>) -> Kind<'tcx> {
|
fn from(r: ty::Region<'tcx>) -> Kind<'tcx> {
|
||||||
// Ensure we can use the tag bits.
|
UnpackedKind::Lifetime(r).pack()
|
||||||
assert_eq!(mem::align_of_val(r) & TAG_MASK, 0);
|
|
||||||
|
|
||||||
let ptr = r as *const _ as usize;
|
|
||||||
Kind {
|
|
||||||
ptr: unsafe {
|
|
||||||
NonZero::new_unchecked(ptr | REGION_TAG)
|
|
||||||
},
|
|
||||||
marker: PhantomData
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
|
||||||
|
fn from(ty: Ty<'tcx>) -> Kind<'tcx> {
|
||||||
|
UnpackedKind::Type(ty).pack()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Kind<'tcx> {
|
impl<'tcx> Kind<'tcx> {
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn downcast<T>(self, tag: usize) -> Option<&'tcx T> {
|
pub fn unpack(self) -> UnpackedKind<'tcx> {
|
||||||
let ptr = self.ptr.get();
|
let ptr = self.ptr.get();
|
||||||
if ptr & TAG_MASK == tag {
|
|
||||||
Some(&*((ptr & !TAG_MASK) as *const _))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn as_type(self) -> Option<Ty<'tcx>> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.downcast(TYPE_TAG)
|
match ptr & TAG_MASK {
|
||||||
|
REGION_TAG => UnpackedKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)),
|
||||||
|
TYPE_TAG => UnpackedKind::Type(&*((ptr & !TAG_MASK) as *const _)),
|
||||||
|
_ => intrinsics::unreachable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn as_region(self) -> Option<ty::Region<'tcx>> {
|
|
||||||
unsafe {
|
|
||||||
self.downcast(REGION_TAG)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for Kind<'tcx> {
|
impl<'tcx> fmt::Debug for Kind<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if let Some(ty) = self.as_type() {
|
match self.unpack() {
|
||||||
write!(f, "{:?}", ty)
|
UnpackedKind::Lifetime(lt) => write!(f, "{:?}", lt),
|
||||||
} else if let Some(r) = self.as_region() {
|
UnpackedKind::Type(ty) => write!(f, "{:?}", ty),
|
||||||
write!(f, "{:?}", r)
|
|
||||||
} else {
|
|
||||||
write!(f, "<unknown @ {:p}>", self.ptr.get() as *const ())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> fmt::Display for Kind<'tcx> {
|
impl<'tcx> fmt::Display for Kind<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if let Some(ty) = self.as_type() {
|
match self.unpack() {
|
||||||
write!(f, "{}", ty)
|
UnpackedKind::Lifetime(lt) => write!(f, "{}", lt),
|
||||||
} else if let Some(r) = self.as_region() {
|
UnpackedKind::Type(ty) => write!(f, "{}", ty),
|
||||||
write!(f, "{}", r)
|
|
||||||
} else {
|
|
||||||
// FIXME(RFC 2000): extend this if/else chain when we support const generic.
|
|
||||||
unimplemented!();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
|
impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
|
||||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||||
if let Some(ty) = self.as_type() {
|
match self.unpack() {
|
||||||
Kind::from(ty.fold_with(folder))
|
UnpackedKind::Lifetime(lt) => lt.fold_with(folder).into(),
|
||||||
} else if let Some(r) = self.as_region() {
|
UnpackedKind::Type(ty) => ty.fold_with(folder).into(),
|
||||||
Kind::from(r.fold_with(folder))
|
|
||||||
} else {
|
|
||||||
bug!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||||
if let Some(ty) = self.as_type() {
|
match self.unpack() {
|
||||||
ty.visit_with(visitor)
|
UnpackedKind::Lifetime(lt) => lt.visit_with(visitor),
|
||||||
} else if let Some(r) = self.as_region() {
|
UnpackedKind::Type(ty) => ty.visit_with(visitor),
|
||||||
r.visit_with(visitor)
|
|
||||||
} else {
|
|
||||||
bug!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,16 +132,17 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
|
|||||||
impl<'tcx> Encodable for Kind<'tcx> {
|
impl<'tcx> Encodable for Kind<'tcx> {
|
||||||
fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
|
fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
|
||||||
e.emit_enum("Kind", |e| {
|
e.emit_enum("Kind", |e| {
|
||||||
if let Some(ty) = self.as_type() {
|
match self.unpack() {
|
||||||
|
UnpackedKind::Lifetime(lt) => {
|
||||||
|
e.emit_enum_variant("Region", REGION_TAG, 1, |e| {
|
||||||
|
e.emit_enum_variant_arg(0, |e| lt.encode(e))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
UnpackedKind::Type(ty) => {
|
||||||
e.emit_enum_variant("Ty", TYPE_TAG, 1, |e| {
|
e.emit_enum_variant("Ty", TYPE_TAG, 1, |e| {
|
||||||
e.emit_enum_variant_arg(0, |e| ty.encode(e))
|
e.emit_enum_variant_arg(0, |e| ty.encode(e))
|
||||||
})
|
})
|
||||||
} else if let Some(r) = self.as_region() {
|
}
|
||||||
e.emit_enum_variant("Region", REGION_TAG, 1, |e| {
|
|
||||||
e.emit_enum_variant_arg(0, |e| r.encode(e))
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
bug!()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -247,7 +235,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
|
|||||||
let def = types.next().unwrap();
|
let def = types.next().unwrap();
|
||||||
let ty = mk_type(def, substs);
|
let ty = mk_type(def, substs);
|
||||||
assert_eq!(def.index as usize, substs.len());
|
assert_eq!(def.index as usize, substs.len());
|
||||||
substs.push(Kind::from(ty));
|
substs.push(ty.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
for def in &defs.regions {
|
for def in &defs.regions {
|
||||||
@ -269,26 +257,42 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
|
pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
|
||||||
self.iter().filter_map(|k| k.as_type())
|
self.iter().filter_map(|k| {
|
||||||
|
if let UnpackedKind::Type(ty) = k.unpack() {
|
||||||
|
Some(ty)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=ty::Region<'tcx>> + 'a {
|
pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=ty::Region<'tcx>> + 'a {
|
||||||
self.iter().filter_map(|k| k.as_region())
|
self.iter().filter_map(|k| {
|
||||||
|
if let UnpackedKind::Lifetime(lt) = k.unpack() {
|
||||||
|
Some(lt)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn type_at(&self, i: usize) -> Ty<'tcx> {
|
pub fn type_at(&self, i: usize) -> Ty<'tcx> {
|
||||||
self[i].as_type().unwrap_or_else(|| {
|
if let UnpackedKind::Type(ty) = self[i].unpack() {
|
||||||
|
ty
|
||||||
|
} else {
|
||||||
bug!("expected type for param #{} in {:?}", i, self);
|
bug!("expected type for param #{} in {:?}", i, self);
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
|
pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
|
||||||
self[i].as_region().unwrap_or_else(|| {
|
if let UnpackedKind::Lifetime(lt) = self[i].unpack() {
|
||||||
|
lt
|
||||||
|
} else {
|
||||||
bug!("expected region for param #{} in {:?}", i, self);
|
bug!("expected region for param #{} in {:?}", i, self);
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -413,13 +417,12 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
|
|||||||
// the specialized routine `ty::replace_late_regions()`.
|
// the specialized routine `ty::replace_late_regions()`.
|
||||||
match *r {
|
match *r {
|
||||||
ty::ReEarlyBound(data) => {
|
ty::ReEarlyBound(data) => {
|
||||||
let r = self.substs.get(data.index as usize)
|
let r = self.substs.get(data.index as usize).map(|k| k.unpack());
|
||||||
.and_then(|k| k.as_region());
|
|
||||||
match r {
|
match r {
|
||||||
Some(r) => {
|
Some(UnpackedKind::Lifetime(lt)) => {
|
||||||
self.shift_region_through_binders(r)
|
self.shift_region_through_binders(lt)
|
||||||
}
|
}
|
||||||
None => {
|
_ => {
|
||||||
let span = self.span.unwrap_or(DUMMY_SP);
|
let span = self.span.unwrap_or(DUMMY_SP);
|
||||||
span_bug!(
|
span_bug!(
|
||||||
span,
|
span,
|
||||||
@ -470,11 +473,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
|
|||||||
impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
|
||||||
fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
|
fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
// Look up the type in the substitutions. It really should be in there.
|
// Look up the type in the substitutions. It really should be in there.
|
||||||
let opt_ty = self.substs.get(p.idx as usize)
|
let opt_ty = self.substs.get(p.idx as usize).map(|k| k.unpack());
|
||||||
.and_then(|k| k.as_type());
|
|
||||||
let ty = match opt_ty {
|
let ty = match opt_ty {
|
||||||
Some(t) => t,
|
Some(UnpackedKind::Type(ty)) => ty,
|
||||||
None => {
|
_ => {
|
||||||
let span = self.span.unwrap_or(DUMMY_SP);
|
let span = self.span.unwrap_or(DUMMY_SP);
|
||||||
span_bug!(
|
span_bug!(
|
||||||
span,
|
span,
|
||||||
@ -600,7 +602,7 @@ impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> {
|
|||||||
ty::TraitRef {
|
ty::TraitRef {
|
||||||
def_id: trait_ref.def_id,
|
def_id: trait_ref.def_id,
|
||||||
substs: tcx.mk_substs(
|
substs: tcx.mk_substs(
|
||||||
iter::once(Kind::from(self_ty)).chain(trait_ref.substs.iter().cloned()))
|
iter::once(self_ty.into()).chain(trait_ref.substs.iter().cloned()))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ use middle::const_val::ConstVal;
|
|||||||
use traits::{self, Reveal};
|
use traits::{self, Reveal};
|
||||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
use ty::fold::TypeVisitor;
|
use ty::fold::TypeVisitor;
|
||||||
use ty::subst::{Subst, Kind};
|
use ty::subst::{Subst, UnpackedKind};
|
||||||
use ty::TypeVariants::*;
|
use ty::TypeVariants::*;
|
||||||
use util::common::ErrorReported;
|
use util::common::ErrorReported;
|
||||||
use middle::lang_items;
|
use middle::lang_items;
|
||||||
@ -509,17 +509,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
let result = item_substs.iter().zip(impl_substs.iter())
|
let result = item_substs.iter().zip(impl_substs.iter())
|
||||||
.filter(|&(_, &k)| {
|
.filter(|&(_, &k)| {
|
||||||
if let Some(&ty::RegionKind::ReEarlyBound(ref ebr)) = k.as_region() {
|
match k.unpack() {
|
||||||
|
UnpackedKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => {
|
||||||
!impl_generics.region_param(ebr, self).pure_wrt_drop
|
!impl_generics.region_param(ebr, self).pure_wrt_drop
|
||||||
} else if let Some(&ty::TyS {
|
}
|
||||||
|
UnpackedKind::Type(&ty::TyS {
|
||||||
sty: ty::TypeVariants::TyParam(ref pt), ..
|
sty: ty::TypeVariants::TyParam(ref pt), ..
|
||||||
}) = k.as_type() {
|
}) => {
|
||||||
!impl_generics.type_param(pt, self).pure_wrt_drop
|
!impl_generics.type_param(pt, self).pure_wrt_drop
|
||||||
} else {
|
}
|
||||||
|
UnpackedKind::Lifetime(_) | UnpackedKind::Type(_) => {
|
||||||
// not a type or region param - this should be reported
|
// not a type or region param - this should be reported
|
||||||
// as an error.
|
// as an error.
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}).map(|(&item_param, _)| item_param).collect();
|
}).map(|(&item_param, _)| item_param).collect();
|
||||||
debug!("destructor_constraint({:?}) = {:?}", def.did, result);
|
debug!("destructor_constraint({:?}) = {:?}", def.did, result);
|
||||||
result
|
result
|
||||||
@ -596,7 +600,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||||||
// Objects must be alive in order for their destructor
|
// Objects must be alive in order for their destructor
|
||||||
// to be called.
|
// to be called.
|
||||||
ty::TyDynamic(..) => Ok(ty::DtorckConstraint {
|
ty::TyDynamic(..) => Ok(ty::DtorckConstraint {
|
||||||
outlives: vec![Kind::from(ty)],
|
outlives: vec![ty.into()],
|
||||||
dtorck_types: vec![],
|
dtorck_types: vec![],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -878,7 +878,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
|||||||
ty::TyAdt(adt, substs) => {
|
ty::TyAdt(adt, substs) => {
|
||||||
if adt.is_box() {
|
if adt.is_box() {
|
||||||
// Use T as the sub pattern type of Box<T>.
|
// Use T as the sub pattern type of Box<T>.
|
||||||
vec![substs[0].as_type().unwrap()]
|
vec![substs.type_at(0)]
|
||||||
} else {
|
} else {
|
||||||
adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
|
adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
|
||||||
let is_visible = adt.is_enum()
|
let is_visible = adt.is_enum()
|
||||||
|
@ -17,7 +17,7 @@ use driver;
|
|||||||
use rustc_lint;
|
use rustc_lint;
|
||||||
use rustc_resolve::MakeGlobMap;
|
use rustc_resolve::MakeGlobMap;
|
||||||
use rustc::middle::region;
|
use rustc::middle::region;
|
||||||
use rustc::ty::subst::{Kind, Subst};
|
use rustc::ty::subst::Subst;
|
||||||
use rustc::traits::{ObligationCause, Reveal};
|
use rustc::traits::{ObligationCause, Reveal};
|
||||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc::ty::maps::OnDiskCache;
|
use rustc::ty::maps::OnDiskCache;
|
||||||
@ -468,7 +468,7 @@ fn subst_ty_renumber_bound() {
|
|||||||
env.t_fn(&[t_param], env.t_nil())
|
env.t_fn(&[t_param], env.t_nil())
|
||||||
};
|
};
|
||||||
|
|
||||||
let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]);
|
let substs = env.infcx.tcx.intern_substs(&[t_rptr_bound1.into()]);
|
||||||
let t_substituted = t_source.subst(env.infcx.tcx, substs);
|
let t_substituted = t_source.subst(env.infcx.tcx, substs);
|
||||||
|
|
||||||
// t_expected = fn(&'a isize)
|
// t_expected = fn(&'a isize)
|
||||||
@ -503,7 +503,7 @@ fn subst_ty_renumber_some_bounds() {
|
|||||||
env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
|
env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
|
||||||
};
|
};
|
||||||
|
|
||||||
let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]);
|
let substs = env.infcx.tcx.intern_substs(&[t_rptr_bound1.into()]);
|
||||||
let t_substituted = t_source.subst(env.infcx.tcx, substs);
|
let t_substituted = t_source.subst(env.infcx.tcx, substs);
|
||||||
|
|
||||||
// t_expected = (&'a isize, fn(&'a isize))
|
// t_expected = (&'a isize, fn(&'a isize))
|
||||||
@ -565,7 +565,7 @@ fn subst_region_renumber_region() {
|
|||||||
env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
|
env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
|
||||||
};
|
};
|
||||||
|
|
||||||
let substs = env.infcx.tcx.intern_substs(&[Kind::from(re_bound1)]);
|
let substs = env.infcx.tcx.intern_substs(&[re_bound1.into()]);
|
||||||
let t_substituted = t_source.subst(env.infcx.tcx, substs);
|
let t_substituted = t_source.subst(env.infcx.tcx, substs);
|
||||||
|
|
||||||
// t_expected = fn(&'a isize)
|
// t_expected = fn(&'a isize)
|
||||||
|
@ -152,6 +152,12 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||||||
NON_SNAKE_CASE,
|
NON_SNAKE_CASE,
|
||||||
NON_UPPER_CASE_GLOBALS);
|
NON_UPPER_CASE_GLOBALS);
|
||||||
|
|
||||||
|
add_lint_group!(sess,
|
||||||
|
"nonstandard_style",
|
||||||
|
NON_CAMEL_CASE_TYPES,
|
||||||
|
NON_SNAKE_CASE,
|
||||||
|
NON_UPPER_CASE_GLOBALS);
|
||||||
|
|
||||||
add_lint_group!(sess,
|
add_lint_group!(sess,
|
||||||
"unused",
|
"unused",
|
||||||
UNUSED_IMPORTS,
|
UNUSED_IMPORTS,
|
||||||
|
@ -7,7 +7,7 @@ use rustc::middle::const_val::ConstVal;
|
|||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::traits::Reveal;
|
use rustc::traits::Reveal;
|
||||||
use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout};
|
use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout};
|
||||||
use rustc::ty::subst::{Subst, Substs, Kind};
|
use rustc::ty::subst::{Subst, Substs};
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
use syntax::codemap::{self, DUMMY_SP};
|
use syntax::codemap::{self, DUMMY_SP};
|
||||||
@ -1663,6 +1663,6 @@ pub fn resolve_drop_in_place<'a, 'tcx>(
|
|||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> ty::Instance<'tcx> {
|
) -> ty::Instance<'tcx> {
|
||||||
let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem);
|
let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem);
|
||||||
let substs = tcx.intern_substs(&[Kind::from(ty)]);
|
let substs = tcx.intern_substs(&[ty.into()]);
|
||||||
ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap()
|
ty::Instance::resolve(tcx, ty::ParamEnv::empty(Reveal::All), def_id, substs).unwrap()
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ fn fn_once_adapter_instance<'a, 'tcx>(
|
|||||||
assert_eq!(sig.inputs().len(), 1);
|
assert_eq!(sig.inputs().len(), 1);
|
||||||
let substs = tcx.mk_substs([
|
let substs = tcx.mk_substs([
|
||||||
Kind::from(self_ty),
|
Kind::from(self_ty),
|
||||||
Kind::from(sig.inputs()[0]),
|
sig.inputs()[0].into(),
|
||||||
].iter().cloned());
|
].iter().cloned());
|
||||||
|
|
||||||
debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
|
debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
|
||||||
@ -153,7 +153,7 @@ pub fn resolve_drop_in_place<'a, 'tcx>(
|
|||||||
-> ty::Instance<'tcx>
|
-> ty::Instance<'tcx>
|
||||||
{
|
{
|
||||||
let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
|
let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
|
||||||
let substs = tcx.intern_substs(&[Kind::from(ty)]);
|
let substs = tcx.intern_substs(&[ty.into()]);
|
||||||
Instance::resolve(tcx, ty::ParamEnv::empty(traits::Reveal::All), def_id, substs).unwrap()
|
Instance::resolve(tcx, ty::ParamEnv::empty(traits::Reveal::All), def_id, substs).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ use rustc::middle::const_val::ConstVal;
|
|||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
|
use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
|
||||||
use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior};
|
use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior};
|
||||||
use rustc::ty::subst::{Kind, Substs};
|
use rustc::ty::subst::Substs;
|
||||||
use util::dump_mir;
|
use util::dump_mir;
|
||||||
use util::liveness::{self, LivenessMode};
|
use util::liveness::{self, LivenessMode};
|
||||||
use rustc_const_math::ConstInt;
|
use rustc_const_math::ConstInt;
|
||||||
@ -858,8 +858,8 @@ impl MirPass for StateTransform {
|
|||||||
// Compute GeneratorState<yield_ty, return_ty>
|
// Compute GeneratorState<yield_ty, return_ty>
|
||||||
let state_did = tcx.lang_items().gen_state().unwrap();
|
let state_did = tcx.lang_items().gen_state().unwrap();
|
||||||
let state_adt_ref = tcx.adt_def(state_did);
|
let state_adt_ref = tcx.adt_def(state_did);
|
||||||
let state_substs = tcx.mk_substs([Kind::from(yield_ty),
|
let state_substs = tcx.mk_substs([yield_ty.into(),
|
||||||
Kind::from(mir.return_ty())].iter());
|
mir.return_ty().into()].iter());
|
||||||
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
|
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
|
||||||
|
|
||||||
// We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
|
// We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
|
||||||
|
@ -59,6 +59,7 @@ use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
|
|||||||
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
|
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
|
||||||
use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue};
|
use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue};
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
|
use syntax::ptr::P;
|
||||||
|
|
||||||
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
|
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
|
||||||
use errors::{DiagnosticBuilder, DiagnosticId};
|
use errors::{DiagnosticBuilder, DiagnosticId};
|
||||||
@ -2329,17 +2330,17 @@ impl<'a> Resolver<'a> {
|
|||||||
|
|
||||||
// check that all of the arms in an or-pattern have exactly the
|
// check that all of the arms in an or-pattern have exactly the
|
||||||
// same set of bindings, with the same binding modes for each.
|
// same set of bindings, with the same binding modes for each.
|
||||||
fn check_consistent_bindings(&mut self, arm: &Arm) {
|
fn check_consistent_bindings(&mut self, pats: &[P<Pat>]) {
|
||||||
if arm.pats.is_empty() {
|
if pats.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut missing_vars = FxHashMap();
|
let mut missing_vars = FxHashMap();
|
||||||
let mut inconsistent_vars = FxHashMap();
|
let mut inconsistent_vars = FxHashMap();
|
||||||
for (i, p) in arm.pats.iter().enumerate() {
|
for (i, p) in pats.iter().enumerate() {
|
||||||
let map_i = self.binding_mode_map(&p);
|
let map_i = self.binding_mode_map(&p);
|
||||||
|
|
||||||
for (j, q) in arm.pats.iter().enumerate() {
|
for (j, q) in pats.iter().enumerate() {
|
||||||
if i == j {
|
if i == j {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2404,9 +2405,8 @@ impl<'a> Resolver<'a> {
|
|||||||
self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list);
|
self.resolve_pattern(&pattern, PatternSource::Match, &mut bindings_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This has to happen *after* we determine which
|
// This has to happen *after* we determine which pat_idents are variants
|
||||||
// pat_idents are variants
|
self.check_consistent_bindings(&arm.pats);
|
||||||
self.check_consistent_bindings(arm);
|
|
||||||
|
|
||||||
walk_list!(self, visit_expr, &arm.guard);
|
walk_list!(self, visit_expr, &arm.guard);
|
||||||
self.visit_expr(&arm.body);
|
self.visit_expr(&arm.body);
|
||||||
@ -2490,7 +2490,9 @@ impl<'a> Resolver<'a> {
|
|||||||
&ident.node.name.as_str())
|
&ident.node.name.as_str())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Some(..) if pat_src == PatternSource::Match => {
|
Some(..) if pat_src == PatternSource::Match ||
|
||||||
|
pat_src == PatternSource::IfLet ||
|
||||||
|
pat_src == PatternSource::WhileLet => {
|
||||||
// `Variant1(a) | Variant2(a)`, ok
|
// `Variant1(a) | Variant2(a)`, ok
|
||||||
// Reuse definition from the first `a`.
|
// Reuse definition from the first `a`.
|
||||||
def = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident.node];
|
def = self.ribs[ValueNS].last_mut().unwrap().bindings[&ident.node];
|
||||||
@ -3480,11 +3482,16 @@ impl<'a> Resolver<'a> {
|
|||||||
visit::walk_expr(self, expr);
|
visit::walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
|
ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
|
||||||
self.visit_expr(subexpression);
|
self.visit_expr(subexpression);
|
||||||
|
|
||||||
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||||
self.resolve_pattern(pattern, PatternSource::IfLet, &mut FxHashMap());
|
let mut bindings_list = FxHashMap();
|
||||||
|
for pat in pats {
|
||||||
|
self.resolve_pattern(pat, PatternSource::IfLet, &mut bindings_list);
|
||||||
|
}
|
||||||
|
// This has to happen *after* we determine which pat_idents are variants
|
||||||
|
self.check_consistent_bindings(pats);
|
||||||
self.visit_block(if_block);
|
self.visit_block(if_block);
|
||||||
self.ribs[ValueNS].pop();
|
self.ribs[ValueNS].pop();
|
||||||
|
|
||||||
@ -3500,11 +3507,16 @@ impl<'a> Resolver<'a> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => {
|
ExprKind::WhileLet(ref pats, ref subexpression, ref block, label) => {
|
||||||
self.with_resolved_label(label, expr.id, |this| {
|
self.with_resolved_label(label, expr.id, |this| {
|
||||||
this.visit_expr(subexpression);
|
this.visit_expr(subexpression);
|
||||||
this.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
this.ribs[ValueNS].push(Rib::new(NormalRibKind));
|
||||||
this.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap());
|
let mut bindings_list = FxHashMap();
|
||||||
|
for pat in pats {
|
||||||
|
this.resolve_pattern(pat, PatternSource::WhileLet, &mut bindings_list);
|
||||||
|
}
|
||||||
|
// This has to happen *after* we determine which pat_idents are variants
|
||||||
|
this.check_consistent_bindings(pats);
|
||||||
this.visit_block(block);
|
this.visit_block(block);
|
||||||
this.ribs[ValueNS].pop();
|
this.ribs[ValueNS].pop();
|
||||||
});
|
});
|
||||||
|
@ -1031,6 +1031,81 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_var_decl_multi(&mut self, pats: &'l [P<ast::Pat>]) {
|
||||||
|
let mut collector = PathCollector::new();
|
||||||
|
for pattern in pats {
|
||||||
|
// collect paths from the arm's patterns
|
||||||
|
collector.visit_pat(&pattern);
|
||||||
|
self.visit_pat(&pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
// process collected paths
|
||||||
|
for (id, i, sp, immut) in collector.collected_idents {
|
||||||
|
match self.save_ctxt.get_path_def(id) {
|
||||||
|
HirDef::Local(id) => {
|
||||||
|
let mut value = if immut == ast::Mutability::Immutable {
|
||||||
|
self.span.snippet(sp).to_string()
|
||||||
|
} else {
|
||||||
|
"<mutable>".to_string()
|
||||||
|
};
|
||||||
|
let hir_id = self.tcx.hir.node_to_hir_id(id);
|
||||||
|
let typ = self.save_ctxt
|
||||||
|
.tables
|
||||||
|
.node_id_to_type_opt(hir_id)
|
||||||
|
.map(|t| t.to_string())
|
||||||
|
.unwrap_or(String::new());
|
||||||
|
value.push_str(": ");
|
||||||
|
value.push_str(&typ);
|
||||||
|
|
||||||
|
if !self.span.filter_generated(Some(sp), sp) {
|
||||||
|
let qualname = format!("{}${}", i.to_string(), id);
|
||||||
|
let id = ::id_from_node_id(id, &self.save_ctxt);
|
||||||
|
let span = self.span_from_span(sp);
|
||||||
|
|
||||||
|
self.dumper.dump_def(
|
||||||
|
&Access {
|
||||||
|
public: false,
|
||||||
|
reachable: false,
|
||||||
|
},
|
||||||
|
Def {
|
||||||
|
kind: DefKind::Local,
|
||||||
|
id,
|
||||||
|
span,
|
||||||
|
name: i.to_string(),
|
||||||
|
qualname,
|
||||||
|
value: typ,
|
||||||
|
parent: None,
|
||||||
|
children: vec![],
|
||||||
|
decl_id: None,
|
||||||
|
docs: String::new(),
|
||||||
|
sig: None,
|
||||||
|
attributes: vec![],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HirDef::StructCtor(..) |
|
||||||
|
HirDef::VariantCtor(..) |
|
||||||
|
HirDef::Const(..) |
|
||||||
|
HirDef::AssociatedConst(..) |
|
||||||
|
HirDef::Struct(..) |
|
||||||
|
HirDef::Variant(..) |
|
||||||
|
HirDef::TyAlias(..) |
|
||||||
|
HirDef::AssociatedTy(..) |
|
||||||
|
HirDef::SelfTy(..) => {
|
||||||
|
self.dump_path_ref(id, &ast::Path::from_ident(sp, i));
|
||||||
|
}
|
||||||
|
def => error!(
|
||||||
|
"unexpected definition kind when processing collected idents: {:?}",
|
||||||
|
def
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (id, ref path) in collector.collected_paths {
|
||||||
|
self.process_path(id, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
|
fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
|
||||||
// The local could declare multiple new vars, we must walk the
|
// The local could declare multiple new vars, we must walk the
|
||||||
@ -1622,17 +1697,21 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
|||||||
v.nest_scope(ex.id, |v| v.visit_expr(body))
|
v.nest_scope(ex.id, |v| v.visit_expr(body))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
|
ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) => {
|
||||||
ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
|
|
||||||
let value = self.span.snippet(subexpression.span);
|
let value = self.span.snippet(subexpression.span);
|
||||||
self.process_var_decl(pattern, value);
|
self.process_var_decl(pattern, value);
|
||||||
debug!("for loop, walk sub-expr: {:?}", subexpression.node);
|
debug!("for loop, walk sub-expr: {:?}", subexpression.node);
|
||||||
self.visit_expr(subexpression);
|
self.visit_expr(subexpression);
|
||||||
visit::walk_block(self, block);
|
visit::walk_block(self, block);
|
||||||
}
|
}
|
||||||
ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
|
ast::ExprKind::WhileLet(ref pats, ref subexpression, ref block, _) => {
|
||||||
let value = self.span.snippet(subexpression.span);
|
self.process_var_decl_multi(pats);
|
||||||
self.process_var_decl(pattern, value);
|
debug!("for loop, walk sub-expr: {:?}", subexpression.node);
|
||||||
|
self.visit_expr(subexpression);
|
||||||
|
visit::walk_block(self, block);
|
||||||
|
}
|
||||||
|
ast::ExprKind::IfLet(ref pats, ref subexpression, ref block, ref opt_else) => {
|
||||||
|
self.process_var_decl_multi(pats);
|
||||||
self.visit_expr(subexpression);
|
self.visit_expr(subexpression);
|
||||||
visit::walk_block(self, block);
|
visit::walk_block(self, block);
|
||||||
opt_else.as_ref().map(|el| self.visit_expr(el));
|
opt_else.as_ref().map(|el| self.visit_expr(el));
|
||||||
@ -1661,79 +1740,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_arm(&mut self, arm: &'l ast::Arm) {
|
fn visit_arm(&mut self, arm: &'l ast::Arm) {
|
||||||
let mut collector = PathCollector::new();
|
self.process_var_decl_multi(&arm.pats);
|
||||||
for pattern in &arm.pats {
|
|
||||||
// collect paths from the arm's patterns
|
|
||||||
collector.visit_pat(&pattern);
|
|
||||||
self.visit_pat(&pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
// process collected paths
|
|
||||||
for (id, i, sp, immut) in collector.collected_idents {
|
|
||||||
match self.save_ctxt.get_path_def(id) {
|
|
||||||
HirDef::Local(id) => {
|
|
||||||
let mut value = if immut == ast::Mutability::Immutable {
|
|
||||||
self.span.snippet(sp).to_string()
|
|
||||||
} else {
|
|
||||||
"<mutable>".to_string()
|
|
||||||
};
|
|
||||||
let hir_id = self.tcx.hir.node_to_hir_id(id);
|
|
||||||
let typ = self.save_ctxt
|
|
||||||
.tables
|
|
||||||
.node_id_to_type_opt(hir_id)
|
|
||||||
.map(|t| t.to_string())
|
|
||||||
.unwrap_or(String::new());
|
|
||||||
value.push_str(": ");
|
|
||||||
value.push_str(&typ);
|
|
||||||
|
|
||||||
if !self.span.filter_generated(Some(sp), sp) {
|
|
||||||
let qualname = format!("{}${}", i.to_string(), id);
|
|
||||||
let id = ::id_from_node_id(id, &self.save_ctxt);
|
|
||||||
let span = self.span_from_span(sp);
|
|
||||||
|
|
||||||
self.dumper.dump_def(
|
|
||||||
&Access {
|
|
||||||
public: false,
|
|
||||||
reachable: false,
|
|
||||||
},
|
|
||||||
Def {
|
|
||||||
kind: DefKind::Local,
|
|
||||||
id,
|
|
||||||
span,
|
|
||||||
name: i.to_string(),
|
|
||||||
qualname,
|
|
||||||
value: typ,
|
|
||||||
parent: None,
|
|
||||||
children: vec![],
|
|
||||||
decl_id: None,
|
|
||||||
docs: String::new(),
|
|
||||||
sig: None,
|
|
||||||
attributes: vec![],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HirDef::StructCtor(..) |
|
|
||||||
HirDef::VariantCtor(..) |
|
|
||||||
HirDef::Const(..) |
|
|
||||||
HirDef::AssociatedConst(..) |
|
|
||||||
HirDef::Struct(..) |
|
|
||||||
HirDef::Variant(..) |
|
|
||||||
HirDef::TyAlias(..) |
|
|
||||||
HirDef::AssociatedTy(..) |
|
|
||||||
HirDef::SelfTy(..) => {
|
|
||||||
self.dump_path_ref(id, &ast::Path::from_ident(sp, i));
|
|
||||||
}
|
|
||||||
def => error!(
|
|
||||||
"unexpected definition kind when processing collected idents: {:?}",
|
|
||||||
def
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (id, ref path) in collector.collected_paths {
|
|
||||||
self.process_path(id, path);
|
|
||||||
}
|
|
||||||
walk_list!(self, visit_expr, &arm.guard);
|
walk_list!(self, visit_expr, &arm.guard);
|
||||||
self.visit_expr(&arm.body);
|
self.visit_expr(&arm.body);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ use value::Value;
|
|||||||
use rustc::traits;
|
use rustc::traits;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::ty::layout::{HasDataLayout, LayoutOf};
|
use rustc::ty::layout::{HasDataLayout, LayoutOf};
|
||||||
use rustc::ty::subst::Kind;
|
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
|
|
||||||
use libc::{c_uint, c_char};
|
use libc::{c_uint, c_char};
|
||||||
@ -413,8 +412,8 @@ pub fn ty_fn_sig<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
|||||||
sig.map_bound(|sig| {
|
sig.map_bound(|sig| {
|
||||||
let state_did = tcx.lang_items().gen_state().unwrap();
|
let state_did = tcx.lang_items().gen_state().unwrap();
|
||||||
let state_adt_ref = tcx.adt_def(state_did);
|
let state_adt_ref = tcx.adt_def(state_did);
|
||||||
let state_substs = tcx.mk_substs([Kind::from(sig.yield_ty),
|
let state_substs = tcx.mk_substs([sig.yield_ty.into(),
|
||||||
Kind::from(sig.return_ty)].iter());
|
sig.return_ty.into()].iter());
|
||||||
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
|
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
|
||||||
|
|
||||||
tcx.mk_fn_sig(iter::once(env_ty),
|
tcx.mk_fn_sig(iter::once(env_ty),
|
||||||
|
@ -19,7 +19,7 @@ use hir::def::Def;
|
|||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use middle::resolve_lifetime as rl;
|
use middle::resolve_lifetime as rl;
|
||||||
use namespace::Namespace;
|
use namespace::Namespace;
|
||||||
use rustc::ty::subst::{Kind, Subst, Substs};
|
use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs};
|
||||||
use rustc::traits;
|
use rustc::traits;
|
||||||
use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable};
|
use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable};
|
||||||
use rustc::ty::wf::object_region_bounds;
|
use rustc::ty::wf::object_region_bounds;
|
||||||
@ -1136,7 +1136,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
|
|
||||||
// Replace all lifetimes with 'static
|
// Replace all lifetimes with 'static
|
||||||
for subst in &mut substs {
|
for subst in &mut substs {
|
||||||
if let Some(_) = subst.as_region() {
|
if let UnpackedKind::Lifetime(_) = subst.unpack() {
|
||||||
*subst = Kind::from(&RegionKind::ReStatic);
|
*subst = Kind::from(&RegionKind::ReStatic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1146,8 +1146,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||||||
|
|
||||||
// Fill in our own generics with the resolved lifetimes
|
// Fill in our own generics with the resolved lifetimes
|
||||||
assert_eq!(lifetimes.len(), generics.own_count());
|
assert_eq!(lifetimes.len(), generics.own_count());
|
||||||
substs.extend(lifetimes.iter().map(|lt|
|
substs.extend(lifetimes.iter().map(|lt| Kind::from(self.ast_region_to_region(lt, None))));
|
||||||
Kind::from(self.ast_region_to_region(lt, None))));
|
|
||||||
|
|
||||||
debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
|
debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
|
||||||
|
|
||||||
|
@ -151,6 +151,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if let PatKind::Ref(..) = pat.node {
|
||||||
|
// When you encounter a `&pat` pattern, reset to "by
|
||||||
|
// value". This is so that `x` and `y` here are by value,
|
||||||
|
// as they appear to be:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// match &(&22, &44) {
|
||||||
|
// (&x, &y) => ...
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// cc #46688
|
||||||
|
def_bm = ty::BindByValue(hir::MutImmutable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lose mutability now that we know binding mode and discriminant type.
|
// Lose mutability now that we know binding mode and discriminant type.
|
||||||
|
@ -14,7 +14,7 @@ use hir::def_id::DefId;
|
|||||||
use rustc::infer::{self, InferOk};
|
use rustc::infer::{self, InferOk};
|
||||||
use rustc::infer::outlives::env::OutlivesEnvironment;
|
use rustc::infer::outlives::env::OutlivesEnvironment;
|
||||||
use rustc::middle::region;
|
use rustc::middle::region;
|
||||||
use rustc::ty::subst::{Subst, Substs};
|
use rustc::ty::subst::{Subst, Substs, UnpackedKind};
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::traits::{self, Reveal, ObligationCause};
|
use rustc::traits::{self, Reveal, ObligationCause};
|
||||||
use util::common::ErrorReported;
|
use util::common::ErrorReported;
|
||||||
@ -331,10 +331,9 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for outlive in outlives {
|
for outlive in outlives {
|
||||||
if let Some(r) = outlive.as_region() {
|
match outlive.unpack() {
|
||||||
rcx.sub_regions(origin(), parent_scope, r);
|
UnpackedKind::Lifetime(lt) => rcx.sub_regions(origin(), parent_scope, lt),
|
||||||
} else if let Some(ty) = outlive.as_type() {
|
UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope),
|
||||||
rcx.type_must_outlive(origin(), ty, parent_scope);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
use super::{FnCtxt, Needs};
|
use super::{FnCtxt, Needs};
|
||||||
use super::method::MethodCallee;
|
use super::method::MethodCallee;
|
||||||
use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
|
use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
|
||||||
use rustc::ty::TypeVariants::{TyStr, TyRef};
|
use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt};
|
||||||
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
|
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
|
||||||
use rustc::infer::type_variable::TypeVariableOrigin;
|
use rustc::infer::type_variable::TypeVariableOrigin;
|
||||||
use errors;
|
use errors;
|
||||||
@ -201,10 +201,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
let mutbl = match mt.mutbl {
|
let mutbl = match mt.mutbl {
|
||||||
hir::MutImmutable => AutoBorrowMutability::Immutable,
|
hir::MutImmutable => AutoBorrowMutability::Immutable,
|
||||||
hir::MutMutable => AutoBorrowMutability::Mutable {
|
hir::MutMutable => AutoBorrowMutability::Mutable {
|
||||||
// For initial two-phase borrow
|
// Allow two-phase borrows for binops in initial deployment
|
||||||
// deployment, conservatively omit
|
// since they desugar to methods
|
||||||
// overloaded binary ops.
|
allow_two_phase_borrow: true,
|
||||||
allow_two_phase_borrow: false,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let autoref = Adjustment {
|
let autoref = Adjustment {
|
||||||
@ -219,10 +218,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
let mutbl = match mt.mutbl {
|
let mutbl = match mt.mutbl {
|
||||||
hir::MutImmutable => AutoBorrowMutability::Immutable,
|
hir::MutImmutable => AutoBorrowMutability::Immutable,
|
||||||
hir::MutMutable => AutoBorrowMutability::Mutable {
|
hir::MutMutable => AutoBorrowMutability::Mutable {
|
||||||
// For initial two-phase borrow
|
// Allow two-phase borrows for binops in initial deployment
|
||||||
// deployment, conservatively omit
|
// since they desugar to methods
|
||||||
// overloaded binary ops.
|
allow_two_phase_borrow: true,
|
||||||
allow_two_phase_borrow: false,
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let autoref = Adjustment {
|
let autoref = Adjustment {
|
||||||
@ -301,7 +299,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
if let Some(missing_trait) = missing_trait {
|
if let Some(missing_trait) = missing_trait {
|
||||||
if missing_trait == "std::ops::Add" &&
|
if missing_trait == "std::ops::Add" &&
|
||||||
self.check_str_addition(expr, lhs_expr, lhs_ty,
|
self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
|
||||||
rhs_ty, &mut err) {
|
rhs_ty, &mut err) {
|
||||||
// This has nothing here because it means we did string
|
// This has nothing here because it means we did string
|
||||||
// concatenation (e.g. "Hello " + "World!"). This means
|
// concatenation (e.g. "Hello " + "World!"). This means
|
||||||
@ -330,37 +328,54 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
fn check_str_addition(&self,
|
fn check_str_addition(&self,
|
||||||
expr: &'gcx hir::Expr,
|
expr: &'gcx hir::Expr,
|
||||||
lhs_expr: &'gcx hir::Expr,
|
lhs_expr: &'gcx hir::Expr,
|
||||||
|
rhs_expr: &'gcx hir::Expr,
|
||||||
lhs_ty: Ty<'tcx>,
|
lhs_ty: Ty<'tcx>,
|
||||||
rhs_ty: Ty<'tcx>,
|
rhs_ty: Ty<'tcx>,
|
||||||
err: &mut errors::DiagnosticBuilder) -> bool {
|
err: &mut errors::DiagnosticBuilder) -> bool {
|
||||||
// If this function returns true it means a note was printed, so we don't need
|
|
||||||
// to print the normal "implementation of `std::ops::Add` might be missing" note
|
|
||||||
let mut is_string_addition = false;
|
|
||||||
if let TyRef(_, l_ty) = lhs_ty.sty {
|
|
||||||
if let TyRef(_, r_ty) = rhs_ty.sty {
|
|
||||||
if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr {
|
|
||||||
err.span_label(expr.span,
|
|
||||||
"`+` can't be used to concatenate two `&str` strings");
|
|
||||||
let codemap = self.tcx.sess.codemap();
|
let codemap = self.tcx.sess.codemap();
|
||||||
let suggestion =
|
let msg = "`to_owned()` can be used to create an owned `String` \
|
||||||
match codemap.span_to_snippet(lhs_expr.span) {
|
|
||||||
Ok(lstring) => format!("{}.to_owned()", lstring),
|
|
||||||
_ => format!("<expression>")
|
|
||||||
};
|
|
||||||
err.span_suggestion(lhs_expr.span,
|
|
||||||
&format!("`to_owned()` can be used to create an owned `String` \
|
|
||||||
from a string reference. String concatenation \
|
from a string reference. String concatenation \
|
||||||
appends the string on the right to the string \
|
appends the string on the right to the string \
|
||||||
on the left and may require reallocation. This \
|
on the left and may require reallocation. This \
|
||||||
requires ownership of the string on the left"), suggestion);
|
requires ownership of the string on the left";
|
||||||
is_string_addition = true;
|
// If this function returns true it means a note was printed, so we don't need
|
||||||
|
// to print the normal "implementation of `std::ops::Add` might be missing" note
|
||||||
|
match (&lhs_ty.sty, &rhs_ty.sty) {
|
||||||
|
(&TyRef(_, ref l_ty), &TyRef(_, ref r_ty))
|
||||||
|
if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr => {
|
||||||
|
err.span_label(expr.span,
|
||||||
|
"`+` can't be used to concatenate two `&str` strings");
|
||||||
|
match codemap.span_to_snippet(lhs_expr.span) {
|
||||||
|
Ok(lstring) => err.span_suggestion(lhs_expr.span,
|
||||||
|
msg,
|
||||||
|
format!("{}.to_owned()", lstring)),
|
||||||
|
_ => err.help(msg),
|
||||||
|
};
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
(&TyRef(_, ref l_ty), &TyAdt(..))
|
||||||
|
if l_ty.ty.sty == TyStr && &format!("{:?}", rhs_ty) == "std::string::String" => {
|
||||||
|
err.span_label(expr.span,
|
||||||
|
"`+` can't be used to concatenate a `&str` with a `String`");
|
||||||
|
match codemap.span_to_snippet(lhs_expr.span) {
|
||||||
|
Ok(lstring) => err.span_suggestion(lhs_expr.span,
|
||||||
|
msg,
|
||||||
|
format!("{}.to_owned()", lstring)),
|
||||||
|
_ => err.help(msg),
|
||||||
|
};
|
||||||
|
match codemap.span_to_snippet(rhs_expr.span) {
|
||||||
|
Ok(rstring) => {
|
||||||
|
err.span_suggestion(rhs_expr.span,
|
||||||
|
"you also need to borrow the `String` on the right to \
|
||||||
|
get a `&str`",
|
||||||
|
format!("&{}", rstring));
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
||||||
is_string_addition
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_user_unop(&self,
|
pub fn check_user_unop(&self,
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
//! We walk the set of items and, for each member, generate new constraints.
|
//! We walk the set of items and, for each member, generate new constraints.
|
||||||
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::{Substs, UnpackedKind};
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
@ -381,12 +381,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||||||
debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
|
debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
|
||||||
variance_decl,
|
variance_decl,
|
||||||
variance_i);
|
variance_i);
|
||||||
if let Some(ty) = k.as_type() {
|
match k.unpack() {
|
||||||
self.add_constraints_from_ty(current, ty, variance_i);
|
UnpackedKind::Lifetime(lt) => {
|
||||||
} else if let Some(r) = k.as_region() {
|
self.add_constraints_from_region(current, lt, variance_i)
|
||||||
self.add_constraints_from_region(current, r, variance_i);
|
}
|
||||||
} else {
|
UnpackedKind::Type(ty) => {
|
||||||
bug!();
|
self.add_constraints_from_ty(current, ty, variance_i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -512,7 +512,16 @@ fn separate_supertrait_bounds(mut g: clean::Generics)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_extern_trait(cx: &DocContext, did: DefId) {
|
pub fn record_extern_trait(cx: &DocContext, did: DefId) {
|
||||||
cx.external_traits.borrow_mut().entry(did).or_insert_with(|| {
|
if cx.external_traits.borrow().contains_key(&did) ||
|
||||||
build_external_trait(cx, did)
|
cx.active_extern_traits.borrow().contains(&did)
|
||||||
});
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cx.active_extern_traits.borrow_mut().push(did);
|
||||||
|
|
||||||
|
let trait_ = build_external_trait(cx, did);
|
||||||
|
|
||||||
|
cx.external_traits.borrow_mut().insert(did, trait_);
|
||||||
|
cx.active_extern_traits.borrow_mut().remove_item(&did);
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,9 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
|
|||||||
pub renderinfo: RefCell<RenderInfo>,
|
pub renderinfo: RefCell<RenderInfo>,
|
||||||
/// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
|
/// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
|
||||||
pub external_traits: RefCell<FxHashMap<DefId, clean::Trait>>,
|
pub external_traits: RefCell<FxHashMap<DefId, clean::Trait>>,
|
||||||
|
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
|
||||||
|
/// the same time.
|
||||||
|
pub active_extern_traits: RefCell<Vec<DefId>>,
|
||||||
// The current set of type and lifetime substitutions,
|
// The current set of type and lifetime substitutions,
|
||||||
// for expanding type aliases at the HIR level:
|
// for expanding type aliases at the HIR level:
|
||||||
|
|
||||||
@ -253,6 +256,7 @@ pub fn run_core(search_paths: SearchPaths,
|
|||||||
populated_all_crate_impls: Cell::new(false),
|
populated_all_crate_impls: Cell::new(false),
|
||||||
access_levels: RefCell::new(access_levels),
|
access_levels: RefCell::new(access_levels),
|
||||||
external_traits: Default::default(),
|
external_traits: Default::default(),
|
||||||
|
active_extern_traits: Default::default(),
|
||||||
renderinfo: Default::default(),
|
renderinfo: Default::default(),
|
||||||
ty_substs: Default::default(),
|
ty_substs: Default::default(),
|
||||||
lt_substs: Default::default(),
|
lt_substs: Default::default(),
|
||||||
|
@ -1825,7 +1825,7 @@ impl Path {
|
|||||||
/// If the path is a normal file, this is the file name. If it's the path of a directory, this
|
/// If the path is a normal file, this is the file name. If it's the path of a directory, this
|
||||||
/// is the directory name.
|
/// is the directory name.
|
||||||
///
|
///
|
||||||
/// Returns [`None`] If the path terminates in `..`.
|
/// Returns [`None`] if the path terminates in `..`.
|
||||||
///
|
///
|
||||||
/// [`None`]: ../../std/option/enum.Option.html#variant.None
|
/// [`None`]: ../../std/option/enum.Option.html#variant.None
|
||||||
///
|
///
|
||||||
|
@ -1085,7 +1085,7 @@ pub enum ExprKind {
|
|||||||
/// `if let pat = expr { block } else { expr }`
|
/// `if let pat = expr { block } else { expr }`
|
||||||
///
|
///
|
||||||
/// This is desugared to a `match` expression.
|
/// This is desugared to a `match` expression.
|
||||||
IfLet(P<Pat>, P<Expr>, P<Block>, Option<P<Expr>>),
|
IfLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<P<Expr>>),
|
||||||
/// A while loop, with an optional label
|
/// A while loop, with an optional label
|
||||||
///
|
///
|
||||||
/// `'label: while expr { block }`
|
/// `'label: while expr { block }`
|
||||||
@ -1095,7 +1095,7 @@ pub enum ExprKind {
|
|||||||
/// `'label: while let pat = expr { block }`
|
/// `'label: while let pat = expr { block }`
|
||||||
///
|
///
|
||||||
/// This is desugared to a combination of `loop` and `match` expressions.
|
/// This is desugared to a combination of `loop` and `match` expressions.
|
||||||
WhileLet(P<Pat>, P<Expr>, P<Block>, Option<Label>),
|
WhileLet(Vec<P<Pat>>, P<Expr>, P<Block>, Option<Label>),
|
||||||
/// A for loop, with an optional label
|
/// A for loop, with an optional label
|
||||||
///
|
///
|
||||||
/// `'label: for pat in expr { block }`
|
/// `'label: for pat in expr { block }`
|
||||||
|
@ -446,6 +446,9 @@ declare_features! (
|
|||||||
|
|
||||||
// Use `?` as the Kleene "at most one" operator
|
// Use `?` as the Kleene "at most one" operator
|
||||||
(active, macro_at_most_once_rep, "1.25.0", Some(48075)),
|
(active, macro_at_most_once_rep, "1.25.0", Some(48075)),
|
||||||
|
|
||||||
|
// Multiple patterns with `|` in `if let` and `while let`
|
||||||
|
(active, if_while_or_patterns, "1.26.0", Some(48215)),
|
||||||
);
|
);
|
||||||
|
|
||||||
declare_features! (
|
declare_features! (
|
||||||
@ -1618,6 +1621,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||||||
ast::ExprKind::Catch(_) => {
|
ast::ExprKind::Catch(_) => {
|
||||||
gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
|
gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental");
|
||||||
}
|
}
|
||||||
|
ast::ExprKind::IfLet(ref pats, ..) | ast::ExprKind::WhileLet(ref pats, ..) => {
|
||||||
|
if pats.len() > 1 {
|
||||||
|
gate_feature_post!(&self, if_while_or_patterns, e.span,
|
||||||
|
"multiple patterns in `if let` and `while let` are unstable");
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
visit::walk_expr(self, e);
|
visit::walk_expr(self, e);
|
||||||
|
@ -1210,8 +1210,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
|
|||||||
folder.fold_block(tr),
|
folder.fold_block(tr),
|
||||||
fl.map(|x| folder.fold_expr(x)))
|
fl.map(|x| folder.fold_expr(x)))
|
||||||
}
|
}
|
||||||
ExprKind::IfLet(pat, expr, tr, fl) => {
|
ExprKind::IfLet(pats, expr, tr, fl) => {
|
||||||
ExprKind::IfLet(folder.fold_pat(pat),
|
ExprKind::IfLet(pats.move_map(|pat| folder.fold_pat(pat)),
|
||||||
folder.fold_expr(expr),
|
folder.fold_expr(expr),
|
||||||
folder.fold_block(tr),
|
folder.fold_block(tr),
|
||||||
fl.map(|x| folder.fold_expr(x)))
|
fl.map(|x| folder.fold_expr(x)))
|
||||||
@ -1221,8 +1221,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
|
|||||||
folder.fold_block(body),
|
folder.fold_block(body),
|
||||||
opt_label.map(|label| folder.fold_label(label)))
|
opt_label.map(|label| folder.fold_label(label)))
|
||||||
}
|
}
|
||||||
ExprKind::WhileLet(pat, expr, body, opt_label) => {
|
ExprKind::WhileLet(pats, expr, body, opt_label) => {
|
||||||
ExprKind::WhileLet(folder.fold_pat(pat),
|
ExprKind::WhileLet(pats.move_map(|pat| folder.fold_pat(pat)),
|
||||||
folder.fold_expr(expr),
|
folder.fold_expr(expr),
|
||||||
folder.fold_block(body),
|
folder.fold_block(body),
|
||||||
opt_label.map(|label| folder.fold_label(label)))
|
opt_label.map(|label| folder.fold_label(label)))
|
||||||
|
@ -405,11 +405,14 @@ impl TokenType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
|
/// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
|
||||||
// `IDENT<<u8 as Trait>::AssocTy>`, `IDENT(u8, u8) -> u8`.
|
/// `IDENT<<u8 as Trait>::AssocTy>`.
|
||||||
fn can_continue_type_after_ident(t: &token::Token) -> bool {
|
///
|
||||||
|
/// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes
|
||||||
|
/// that IDENT is not the ident of a fn trait
|
||||||
|
fn can_continue_type_after_non_fn_ident(t: &token::Token) -> bool {
|
||||||
t == &token::ModSep || t == &token::Lt ||
|
t == &token::ModSep || t == &token::Lt ||
|
||||||
t == &token::BinOp(token::Shl) || t == &token::OpenDelim(token::Paren)
|
t == &token::BinOp(token::Shl)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information about the path to a module.
|
/// Information about the path to a module.
|
||||||
@ -1321,7 +1324,7 @@ impl<'a> Parser<'a> {
|
|||||||
pub fn token_is_bare_fn_keyword(&mut self) -> bool {
|
pub fn token_is_bare_fn_keyword(&mut self) -> bool {
|
||||||
self.check_keyword(keywords::Fn) ||
|
self.check_keyword(keywords::Fn) ||
|
||||||
self.check_keyword(keywords::Unsafe) ||
|
self.check_keyword(keywords::Unsafe) ||
|
||||||
self.check_keyword(keywords::Extern)
|
self.check_keyword(keywords::Extern) && self.is_extern_non_path()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eat_label(&mut self) -> Option<Label> {
|
fn eat_label(&mut self) -> Option<Label> {
|
||||||
@ -1619,7 +1622,8 @@ impl<'a> Parser<'a> {
|
|||||||
impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
|
impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus;
|
||||||
TyKind::ImplTrait(bounds)
|
TyKind::ImplTrait(bounds)
|
||||||
} else if self.check_keyword(keywords::Dyn) &&
|
} else if self.check_keyword(keywords::Dyn) &&
|
||||||
self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) {
|
self.look_ahead(1, |t| t.can_begin_bound() &&
|
||||||
|
!can_continue_type_after_non_fn_ident(t)) {
|
||||||
self.bump(); // `dyn`
|
self.bump(); // `dyn`
|
||||||
// Always parse bounds greedily for better error recovery.
|
// Always parse bounds greedily for better error recovery.
|
||||||
let bounds = self.parse_ty_param_bounds()?;
|
let bounds = self.parse_ty_param_bounds()?;
|
||||||
@ -3224,7 +3228,7 @@ impl<'a> Parser<'a> {
|
|||||||
-> PResult<'a, P<Expr>> {
|
-> PResult<'a, P<Expr>> {
|
||||||
let lo = self.prev_span;
|
let lo = self.prev_span;
|
||||||
self.expect_keyword(keywords::Let)?;
|
self.expect_keyword(keywords::Let)?;
|
||||||
let pat = self.parse_pat()?;
|
let pats = self.parse_pats()?;
|
||||||
self.expect(&token::Eq)?;
|
self.expect(&token::Eq)?;
|
||||||
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
||||||
let thn = self.parse_block()?;
|
let thn = self.parse_block()?;
|
||||||
@ -3234,7 +3238,7 @@ impl<'a> Parser<'a> {
|
|||||||
} else {
|
} else {
|
||||||
(thn.span, None)
|
(thn.span, None)
|
||||||
};
|
};
|
||||||
Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pat, expr, thn, els), attrs))
|
Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pats, expr, thn, els), attrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// `move |args| expr`
|
// `move |args| expr`
|
||||||
@ -3325,13 +3329,13 @@ impl<'a> Parser<'a> {
|
|||||||
span_lo: Span,
|
span_lo: Span,
|
||||||
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
|
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
|
||||||
self.expect_keyword(keywords::Let)?;
|
self.expect_keyword(keywords::Let)?;
|
||||||
let pat = self.parse_pat()?;
|
let pats = self.parse_pats()?;
|
||||||
self.expect(&token::Eq)?;
|
self.expect(&token::Eq)?;
|
||||||
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
|
||||||
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
|
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
|
||||||
attrs.extend(iattrs);
|
attrs.extend(iattrs);
|
||||||
let span = span_lo.to(body.span);
|
let span = span_lo.to(body.span);
|
||||||
return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_label), attrs));
|
return Ok(self.mk_expr(span, ExprKind::WhileLet(pats, expr, body, opt_label), attrs));
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse `loop {...}`, `loop` token already eaten
|
// parse `loop {...}`, `loop` token already eaten
|
||||||
|
@ -1767,11 +1767,11 @@ impl<'a> State<'a> {
|
|||||||
self.print_else(e.as_ref().map(|e| &**e))
|
self.print_else(e.as_ref().map(|e| &**e))
|
||||||
}
|
}
|
||||||
// "another else-if-let"
|
// "another else-if-let"
|
||||||
ast::ExprKind::IfLet(ref pat, ref expr, ref then, ref e) => {
|
ast::ExprKind::IfLet(ref pats, ref expr, ref then, ref e) => {
|
||||||
self.cbox(INDENT_UNIT - 1)?;
|
self.cbox(INDENT_UNIT - 1)?;
|
||||||
self.ibox(0)?;
|
self.ibox(0)?;
|
||||||
self.s.word(" else if let ")?;
|
self.s.word(" else if let ")?;
|
||||||
self.print_pat(pat)?;
|
self.print_pats(pats)?;
|
||||||
self.s.space()?;
|
self.s.space()?;
|
||||||
self.word_space("=")?;
|
self.word_space("=")?;
|
||||||
self.print_expr_as_cond(expr)?;
|
self.print_expr_as_cond(expr)?;
|
||||||
@ -1805,10 +1805,10 @@ impl<'a> State<'a> {
|
|||||||
self.print_else(elseopt)
|
self.print_else(elseopt)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_if_let(&mut self, pat: &ast::Pat, expr: &ast::Expr, blk: &ast::Block,
|
pub fn print_if_let(&mut self, pats: &[P<ast::Pat>], expr: &ast::Expr, blk: &ast::Block,
|
||||||
elseopt: Option<&ast::Expr>) -> io::Result<()> {
|
elseopt: Option<&ast::Expr>) -> io::Result<()> {
|
||||||
self.head("if let")?;
|
self.head("if let")?;
|
||||||
self.print_pat(pat)?;
|
self.print_pats(pats)?;
|
||||||
self.s.space()?;
|
self.s.space()?;
|
||||||
self.word_space("=")?;
|
self.word_space("=")?;
|
||||||
self.print_expr_as_cond(expr)?;
|
self.print_expr_as_cond(expr)?;
|
||||||
@ -2109,8 +2109,8 @@ impl<'a> State<'a> {
|
|||||||
ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
|
ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
|
||||||
self.print_if(test, blk, elseopt.as_ref().map(|e| &**e))?;
|
self.print_if(test, blk, elseopt.as_ref().map(|e| &**e))?;
|
||||||
}
|
}
|
||||||
ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => {
|
ast::ExprKind::IfLet(ref pats, ref expr, ref blk, ref elseopt) => {
|
||||||
self.print_if_let(pat, expr, blk, elseopt.as_ref().map(|e| &**e))?;
|
self.print_if_let(pats, expr, blk, elseopt.as_ref().map(|e| &**e))?;
|
||||||
}
|
}
|
||||||
ast::ExprKind::While(ref test, ref blk, opt_label) => {
|
ast::ExprKind::While(ref test, ref blk, opt_label) => {
|
||||||
if let Some(label) = opt_label {
|
if let Some(label) = opt_label {
|
||||||
@ -2122,13 +2122,13 @@ impl<'a> State<'a> {
|
|||||||
self.s.space()?;
|
self.s.space()?;
|
||||||
self.print_block_with_attrs(blk, attrs)?;
|
self.print_block_with_attrs(blk, attrs)?;
|
||||||
}
|
}
|
||||||
ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_label) => {
|
ast::ExprKind::WhileLet(ref pats, ref expr, ref blk, opt_label) => {
|
||||||
if let Some(label) = opt_label {
|
if let Some(label) = opt_label {
|
||||||
self.print_ident(label.ident)?;
|
self.print_ident(label.ident)?;
|
||||||
self.word_space(":")?;
|
self.word_space(":")?;
|
||||||
}
|
}
|
||||||
self.head("while let")?;
|
self.head("while let")?;
|
||||||
self.print_pat(pat)?;
|
self.print_pats(pats)?;
|
||||||
self.s.space()?;
|
self.s.space()?;
|
||||||
self.word_space("=")?;
|
self.word_space("=")?;
|
||||||
self.print_expr_as_cond(expr)?;
|
self.print_expr_as_cond(expr)?;
|
||||||
@ -2664,6 +2664,20 @@ impl<'a> State<'a> {
|
|||||||
self.ann.post(self, NodePat(pat))
|
self.ann.post(self, NodePat(pat))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_pats(&mut self, pats: &[P<ast::Pat>]) -> io::Result<()> {
|
||||||
|
let mut first = true;
|
||||||
|
for p in pats {
|
||||||
|
if first {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
self.s.space()?;
|
||||||
|
self.word_space("|")?;
|
||||||
|
}
|
||||||
|
self.print_pat(p)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> {
|
fn print_arm(&mut self, arm: &ast::Arm) -> io::Result<()> {
|
||||||
// I have no idea why this check is necessary, but here it
|
// I have no idea why this check is necessary, but here it
|
||||||
// is :(
|
// is :(
|
||||||
@ -2674,16 +2688,7 @@ impl<'a> State<'a> {
|
|||||||
self.ibox(0)?;
|
self.ibox(0)?;
|
||||||
self.maybe_print_comment(arm.pats[0].span.lo())?;
|
self.maybe_print_comment(arm.pats[0].span.lo())?;
|
||||||
self.print_outer_attributes(&arm.attrs)?;
|
self.print_outer_attributes(&arm.attrs)?;
|
||||||
let mut first = true;
|
self.print_pats(&arm.pats)?;
|
||||||
for p in &arm.pats {
|
|
||||||
if first {
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
self.s.space()?;
|
|
||||||
self.word_space("|")?;
|
|
||||||
}
|
|
||||||
self.print_pat(p)?;
|
|
||||||
}
|
|
||||||
self.s.space()?;
|
self.s.space()?;
|
||||||
if let Some(ref e) = arm.guard {
|
if let Some(ref e) = arm.guard {
|
||||||
self.word_space("if")?;
|
self.word_space("if")?;
|
||||||
|
@ -705,15 +705,15 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
|||||||
visitor.visit_expr(subexpression);
|
visitor.visit_expr(subexpression);
|
||||||
visitor.visit_block(block);
|
visitor.visit_block(block);
|
||||||
}
|
}
|
||||||
ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
|
ExprKind::IfLet(ref pats, ref subexpression, ref if_block, ref optional_else) => {
|
||||||
visitor.visit_pat(pattern);
|
walk_list!(visitor, visit_pat, pats);
|
||||||
visitor.visit_expr(subexpression);
|
visitor.visit_expr(subexpression);
|
||||||
visitor.visit_block(if_block);
|
visitor.visit_block(if_block);
|
||||||
walk_list!(visitor, visit_expr, optional_else);
|
walk_list!(visitor, visit_expr, optional_else);
|
||||||
}
|
}
|
||||||
ExprKind::WhileLet(ref pattern, ref subexpression, ref block, ref opt_label) => {
|
ExprKind::WhileLet(ref pats, ref subexpression, ref block, ref opt_label) => {
|
||||||
walk_list!(visitor, visit_label, opt_label);
|
walk_list!(visitor, visit_label, opt_label);
|
||||||
visitor.visit_pat(pattern);
|
walk_list!(visitor, visit_pat, pats);
|
||||||
visitor.visit_expr(subexpression);
|
visitor.visit_expr(subexpression);
|
||||||
visitor.visit_block(block);
|
visitor.visit_block(block);
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,6 @@
|
|||||||
// #![feature(rustc_attrs)]
|
// #![feature(rustc_attrs)]
|
||||||
|
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
|
|
||||||
use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
|
|
||||||
|
|
||||||
// This is case outlined by Niko that we want to ensure we reject
|
// This is case outlined by Niko that we want to ensure we reject
|
||||||
// (at least initially).
|
// (at least initially).
|
||||||
@ -182,56 +180,6 @@ fn coerce_index_op() {
|
|||||||
//[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
//[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
|
||||||
}
|
}
|
||||||
|
|
||||||
struct A(i32);
|
|
||||||
|
|
||||||
macro_rules! trivial_binop {
|
|
||||||
($Trait:ident, $m:ident) => {
|
|
||||||
impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trivial_binop!(AddAssign, add_assign);
|
|
||||||
trivial_binop!(SubAssign, sub_assign);
|
|
||||||
trivial_binop!(MulAssign, mul_assign);
|
|
||||||
trivial_binop!(DivAssign, div_assign);
|
|
||||||
trivial_binop!(RemAssign, rem_assign);
|
|
||||||
trivial_binop!(BitAndAssign, bitand_assign);
|
|
||||||
trivial_binop!(BitOrAssign, bitor_assign);
|
|
||||||
trivial_binop!(BitXorAssign, bitxor_assign);
|
|
||||||
trivial_binop!(ShlAssign, shl_assign);
|
|
||||||
trivial_binop!(ShrAssign, shr_assign);
|
|
||||||
|
|
||||||
fn overloaded_binops() {
|
|
||||||
let mut a = A(10);
|
|
||||||
a += a.0;
|
|
||||||
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
a -= a.0;
|
|
||||||
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
a *= a.0;
|
|
||||||
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
a /= a.0;
|
|
||||||
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
a &= a.0;
|
|
||||||
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
a |= a.0;
|
|
||||||
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
a ^= a.0;
|
|
||||||
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
a <<= a.0;
|
|
||||||
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
a >>= a.0;
|
|
||||||
//[lxl]~^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
//[nll]~^^ ERROR cannot use `a.0` because it was mutably borrowed
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
// As a reminder, this is the basic case we want to ensure we handle.
|
// As a reminder, this is the basic case we want to ensure we handle.
|
||||||
@ -252,5 +200,4 @@ fn main() {
|
|||||||
|
|
||||||
coerce_unsized();
|
coerce_unsized();
|
||||||
coerce_index_op();
|
coerce_index_op();
|
||||||
overloaded_binops();
|
|
||||||
}
|
}
|
||||||
|
@ -20,10 +20,5 @@ type A3 = dyn<<dyn as dyn>::dyn>;
|
|||||||
//~^ ERROR cannot find type `dyn` in this scope
|
//~^ ERROR cannot find type `dyn` in this scope
|
||||||
//~| ERROR cannot find type `dyn` in this scope
|
//~| ERROR cannot find type `dyn` in this scope
|
||||||
//~| ERROR Use of undeclared type or module `dyn`
|
//~| ERROR Use of undeclared type or module `dyn`
|
||||||
type A4 = dyn(dyn, dyn) -> dyn;
|
|
||||||
//~^ ERROR cannot find type `dyn` in this scope
|
|
||||||
//~| ERROR cannot find type `dyn` in this scope
|
|
||||||
//~| ERROR cannot find type `dyn` in this scope
|
|
||||||
//~| ERROR cannot find type `dyn` in this scope
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
48
src/test/run-pass/borrowck/two-phase-bin-ops.rs
Normal file
48
src/test/run-pass/borrowck/two-phase-bin-ops.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// revisions: lxl nll
|
||||||
|
|
||||||
|
#![cfg_attr(nll, feature(nll))]
|
||||||
|
|
||||||
|
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
|
||||||
|
use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
|
||||||
|
|
||||||
|
struct A(i32);
|
||||||
|
|
||||||
|
macro_rules! trivial_binop {
|
||||||
|
($Trait:ident, $m:ident) => {
|
||||||
|
impl $Trait<i32> for A { fn $m(&mut self, rhs: i32) { self.0 = rhs; } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trivial_binop!(AddAssign, add_assign);
|
||||||
|
trivial_binop!(SubAssign, sub_assign);
|
||||||
|
trivial_binop!(MulAssign, mul_assign);
|
||||||
|
trivial_binop!(DivAssign, div_assign);
|
||||||
|
trivial_binop!(RemAssign, rem_assign);
|
||||||
|
trivial_binop!(BitAndAssign, bitand_assign);
|
||||||
|
trivial_binop!(BitOrAssign, bitor_assign);
|
||||||
|
trivial_binop!(BitXorAssign, bitxor_assign);
|
||||||
|
trivial_binop!(ShlAssign, shl_assign);
|
||||||
|
trivial_binop!(ShrAssign, shr_assign);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut a = A(10);
|
||||||
|
a += a.0;
|
||||||
|
a -= a.0;
|
||||||
|
a *= a.0;
|
||||||
|
a /= a.0;
|
||||||
|
a &= a.0;
|
||||||
|
a |= a.0;
|
||||||
|
a ^= a.0;
|
||||||
|
a <<= a.0;
|
||||||
|
a >>= a.0;
|
||||||
|
}
|
@ -8,6 +8,8 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
|
// ignore-pretty `dyn ::foo` parses differently in the current epoch
|
||||||
|
|
||||||
#![feature(dyn_trait)]
|
#![feature(dyn_trait)]
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
@ -17,6 +19,8 @@ static BYTE: u8 = 33;
|
|||||||
fn main() {
|
fn main() {
|
||||||
let x: &(dyn 'static + Display) = &BYTE;
|
let x: &(dyn 'static + Display) = &BYTE;
|
||||||
let y: Box<dyn Display + 'static> = Box::new(BYTE);
|
let y: Box<dyn Display + 'static> = Box::new(BYTE);
|
||||||
|
let _: &dyn (Display) = &BYTE;
|
||||||
|
let _: &dyn (::std::fmt::Display) = &BYTE;
|
||||||
let xstr = format!("{}", x);
|
let xstr = format!("{}", x);
|
||||||
let ystr = format!("{}", y);
|
let ystr = format!("{}", y);
|
||||||
assert_eq!(xstr, "33");
|
assert_eq!(xstr, "33");
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#![feature(match_default_bindings)]
|
||||||
|
|
||||||
|
// Test that we "reset" the mode as we pass through a `&` pattern.
|
||||||
|
//
|
||||||
|
// cc #46688
|
||||||
|
|
||||||
|
fn surprise(x: i32) {
|
||||||
|
assert_eq!(x, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = &(1, &2);
|
||||||
|
let (_, &b) = x;
|
||||||
|
surprise(b);
|
||||||
|
}
|
@ -8,8 +8,10 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct S;
|
pub struct S;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Z;
|
pub struct Z;
|
||||||
|
|
||||||
|
pub trait Tr<'a> {}
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
|
|
||||||
use extern::xcrate::Z;
|
use extern::xcrate::Z;
|
||||||
|
|
||||||
|
type A = extern::xcrate::S;
|
||||||
|
type B = for<'a> extern::xcrate::Tr<'a>;
|
||||||
|
|
||||||
fn f() {
|
fn f() {
|
||||||
use extern::xcrate;
|
use extern::xcrate;
|
||||||
use extern::xcrate as ycrate;
|
use extern::xcrate as ycrate;
|
||||||
@ -28,4 +31,5 @@ fn main() {
|
|||||||
assert_eq!(format!("{:?}", s), "S");
|
assert_eq!(format!("{:?}", s), "S");
|
||||||
let z = Z;
|
let z = Z;
|
||||||
assert_eq!(format!("{:?}", z), "Z");
|
assert_eq!(format!("{:?}", z), "Z");
|
||||||
|
assert_eq!(A {}, extern::xcrate::S {});
|
||||||
}
|
}
|
||||||
|
30
src/test/run-pass/rfc-2175-or-if-while-let/basic.rs
Normal file
30
src/test/run-pass/rfc-2175-or-if-while-let/basic.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.
|
||||||
|
|
||||||
|
#![feature(if_while_or_patterns)]
|
||||||
|
|
||||||
|
enum E {
|
||||||
|
V(u8),
|
||||||
|
U(u8),
|
||||||
|
W,
|
||||||
|
}
|
||||||
|
use E::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut e = V(10);
|
||||||
|
|
||||||
|
if let V(x) | U(x) = e {
|
||||||
|
assert_eq!(x, 10);
|
||||||
|
}
|
||||||
|
while let V(x) | U(x) = e {
|
||||||
|
assert_eq!(x, 10);
|
||||||
|
e = W;
|
||||||
|
}
|
||||||
|
}
|
15
src/test/rustdoc/auxiliary/issue-48414.rs
Normal file
15
src/test/rustdoc/auxiliary/issue-48414.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
/// Woah, this trait links to [OtherTrait](OtherTrait)!
|
||||||
|
pub trait SomeTrait {}
|
||||||
|
|
||||||
|
/// Woah, this trait links to [SomeTrait](SomeTrait)!
|
||||||
|
pub trait OtherTrait {}
|
21
src/test/rustdoc/issue-48414.rs
Normal file
21
src/test/rustdoc/issue-48414.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// aux-build:issue-48414.rs
|
||||||
|
|
||||||
|
// ICE when resolving paths for a trait that linked to another trait, when both were in an external
|
||||||
|
// crate
|
||||||
|
|
||||||
|
#![crate_name = "base"]
|
||||||
|
|
||||||
|
extern crate issue_48414;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use issue_48414::{SomeTrait, OtherTrait};
|
18
src/test/ui/feature-gate-if_while_or_patterns.rs
Normal file
18
src/test/ui/feature-gate-if_while_or_patterns.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2018 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 main() {
|
||||||
|
if let 0 | 1 = 0 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
|
||||||
|
;
|
||||||
|
}
|
||||||
|
while let 0 | 1 = 1 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
22
src/test/ui/feature-gate-if_while_or_patterns.stderr
Normal file
22
src/test/ui/feature-gate-if_while_or_patterns.stderr
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
error[E0658]: multiple patterns in `if let` and `while let` are unstable (see issue #48215)
|
||||||
|
--> $DIR/feature-gate-if_while_or_patterns.rs:12:5
|
||||||
|
|
|
||||||
|
12 | / if let 0 | 1 = 0 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
|
||||||
|
13 | | ;
|
||||||
|
14 | | }
|
||||||
|
| |_____^
|
||||||
|
|
|
||||||
|
= help: add #![feature(if_while_or_patterns)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: multiple patterns in `if let` and `while let` are unstable (see issue #48215)
|
||||||
|
--> $DIR/feature-gate-if_while_or_patterns.rs:15:5
|
||||||
|
|
|
||||||
|
15 | / while let 0 | 1 = 1 { //~ ERROR multiple patterns in `if let` and `while let` are unstable
|
||||||
|
16 | | break;
|
||||||
|
17 | | }
|
||||||
|
| |_____^
|
||||||
|
|
|
||||||
|
= help: add #![feature(if_while_or_patterns)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
43
src/test/ui/issue-45157.rs
Normal file
43
src/test/ui/issue-45157.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#![allow(unused)]
|
||||||
|
#![feature(nll)]
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
struct S {
|
||||||
|
a: u8,
|
||||||
|
b: u8,
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
struct Z {
|
||||||
|
c: u8,
|
||||||
|
d: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
union U {
|
||||||
|
s: S,
|
||||||
|
z: Z,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
let mut u = U { s: Default::default() };
|
||||||
|
|
||||||
|
let mref = &mut u.s.a;
|
||||||
|
*mref = 22;
|
||||||
|
|
||||||
|
let nref = &u.z.c;
|
||||||
|
//~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502]
|
||||||
|
println!("{} {}", mref, nref)
|
||||||
|
//~^ ERROR cannot borrow `u.s.a` as mutable because it is also borrowed as immutable [E0502]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
20
src/test/ui/issue-45157.stderr
Normal file
20
src/test/ui/issue-45157.stderr
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
error[E0502]: cannot borrow `u.z.c` as immutable because it is also borrowed as mutable
|
||||||
|
--> $DIR/issue-45157.rs:37:20
|
||||||
|
|
|
||||||
|
34 | let mref = &mut u.s.a;
|
||||||
|
| ---------- mutable borrow occurs here
|
||||||
|
...
|
||||||
|
37 | let nref = &u.z.c;
|
||||||
|
| ^^^^^^ immutable borrow occurs here
|
||||||
|
|
||||||
|
error[E0502]: cannot borrow `u.s.a` as mutable because it is also borrowed as immutable
|
||||||
|
--> $DIR/issue-45157.rs:39:27
|
||||||
|
|
|
||||||
|
37 | let nref = &u.z.c;
|
||||||
|
| ------ immutable borrow occurs here
|
||||||
|
38 | //~^ ERROR cannot borrow `u.z.c` as immutable because it is also borrowed as mutable [E0502]
|
||||||
|
39 | println!("{} {}", mref, nref)
|
||||||
|
| ^^^^ mutable borrow occurs here
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
36
src/test/ui/lint/lint-group-nonstandard-style.rs
Normal file
36
src/test/ui/lint/lint-group-nonstandard-style.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2014–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.
|
||||||
|
|
||||||
|
#![deny(nonstandard_style)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
fn CamelCase() {} //~ ERROR should have a snake
|
||||||
|
|
||||||
|
#[allow(nonstandard_style)]
|
||||||
|
mod test {
|
||||||
|
fn CamelCase() {}
|
||||||
|
|
||||||
|
#[forbid(nonstandard_style)]
|
||||||
|
mod bad {
|
||||||
|
fn CamelCase() {} //~ ERROR should have a snake
|
||||||
|
|
||||||
|
static bad: isize = 1; //~ ERROR should have an upper
|
||||||
|
}
|
||||||
|
|
||||||
|
mod warn {
|
||||||
|
#![warn(nonstandard_style)]
|
||||||
|
|
||||||
|
fn CamelCase() {} //~ WARN should have a snake
|
||||||
|
|
||||||
|
struct snake_case; //~ WARN should have a camel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
67
src/test/ui/lint/lint-group-nonstandard-style.stderr
Normal file
67
src/test/ui/lint/lint-group-nonstandard-style.stderr
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
error: function `CamelCase` should have a snake case name such as `camel_case`
|
||||||
|
--> $DIR/lint-group-nonstandard-style.rs:14:1
|
||||||
|
|
|
||||||
|
14 | fn CamelCase() {} //~ ERROR should have a snake
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lint level defined here
|
||||||
|
--> $DIR/lint-group-nonstandard-style.rs:11:9
|
||||||
|
|
|
||||||
|
11 | #![deny(nonstandard_style)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
= note: #[deny(non_snake_case)] implied by #[deny(nonstandard_style)]
|
||||||
|
|
||||||
|
error: function `CamelCase` should have a snake case name such as `camel_case`
|
||||||
|
--> $DIR/lint-group-nonstandard-style.rs:22:9
|
||||||
|
|
|
||||||
|
22 | fn CamelCase() {} //~ ERROR should have a snake
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lint level defined here
|
||||||
|
--> $DIR/lint-group-nonstandard-style.rs:20:14
|
||||||
|
|
|
||||||
|
20 | #[forbid(nonstandard_style)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
= note: #[forbid(non_snake_case)] implied by #[forbid(nonstandard_style)]
|
||||||
|
|
||||||
|
error: static variable `bad` should have an upper case name such as `BAD`
|
||||||
|
--> $DIR/lint-group-nonstandard-style.rs:24:9
|
||||||
|
|
|
||||||
|
24 | static bad: isize = 1; //~ ERROR should have an upper
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lint level defined here
|
||||||
|
--> $DIR/lint-group-nonstandard-style.rs:20:14
|
||||||
|
|
|
||||||
|
20 | #[forbid(nonstandard_style)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
= note: #[forbid(non_upper_case_globals)] implied by #[forbid(nonstandard_style)]
|
||||||
|
|
||||||
|
warning: function `CamelCase` should have a snake case name such as `camel_case`
|
||||||
|
--> $DIR/lint-group-nonstandard-style.rs:30:9
|
||||||
|
|
|
||||||
|
30 | fn CamelCase() {} //~ WARN should have a snake
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lint level defined here
|
||||||
|
--> $DIR/lint-group-nonstandard-style.rs:28:17
|
||||||
|
|
|
||||||
|
28 | #![warn(nonstandard_style)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
= note: #[warn(non_snake_case)] implied by #[warn(nonstandard_style)]
|
||||||
|
|
||||||
|
warning: type `snake_case` should have a camel case name such as `SnakeCase`
|
||||||
|
--> $DIR/lint-group-nonstandard-style.rs:32:9
|
||||||
|
|
|
||||||
|
32 | struct snake_case; //~ WARN should have a camel
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lint level defined here
|
||||||
|
--> $DIR/lint-group-nonstandard-style.rs:28:17
|
||||||
|
|
|
||||||
|
28 | #![warn(nonstandard_style)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
= note: #[warn(non_camel_case_types)] implied by #[warn(nonstandard_style)]
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
@ -17,6 +17,9 @@ pub fn main() {
|
|||||||
// that won't output for the above string concatenation
|
// that won't output for the above string concatenation
|
||||||
let y = World::Hello + World::Goodbye;
|
let y = World::Hello + World::Goodbye;
|
||||||
//~^ ERROR cannot be applied to type
|
//~^ ERROR cannot be applied to type
|
||||||
|
|
||||||
|
let x = "Hello " + "World!".to_owned();
|
||||||
|
//~^ ERROR cannot be applied to type
|
||||||
}
|
}
|
||||||
|
|
||||||
enum World {
|
enum World {
|
||||||
|
@ -16,5 +16,19 @@ error[E0369]: binary operation `+` cannot be applied to type `World`
|
|||||||
|
|
|
|
||||||
= note: an implementation of `std::ops::Add` might be missing for `World`
|
= note: an implementation of `std::ops::Add` might be missing for `World`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error[E0369]: binary operation `+` cannot be applied to type `&str`
|
||||||
|
--> $DIR/issue-39018.rs:21:13
|
||||||
|
|
|
||||||
|
21 | let x = "Hello " + "World!".to_owned();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `+` can't be used to concatenate a `&str` with a `String`
|
||||||
|
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
|
||||||
|
|
|
||||||
|
21 | let x = "Hello ".to_owned() + "World!".to_owned();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
help: you also need to borrow the `String` on the right to get a `&str`
|
||||||
|
|
|
||||||
|
21 | let x = "Hello " + &"World!".to_owned();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user