Auto merge of #68423 - Centril:rollup-bdjykrv, r=Centril
Rollup of 7 pull requests Successful merges: - #67686 (Simplify NodeHeader by avoiding slices in BTreeMaps with shared roots) - #68140 (Implement `?const` opt-out for trait bounds) - #68313 (Options IP_MULTICAST_TTL and IP_MULTICAST_LOOP are 1 byte on BSD) - #68328 (Actually pass target LLVM args to LLVM) - #68399 (check_match: misc unifications and ICE fixes) - #68415 (tidy: fix most clippy warnings) - #68416 (lowering: cleanup some hofs) Failed merges: r? @ghost
This commit is contained in:
commit
5e8897b7b5
@ -3763,6 +3763,7 @@ dependencies = [
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"serialize",
|
||||
|
@ -1968,7 +1968,7 @@ where
|
||||
(i, false) => i,
|
||||
},
|
||||
(_, Unbounded) => 0,
|
||||
(true, Included(_)) => min_node.keys().len(),
|
||||
(true, Included(_)) => min_node.len(),
|
||||
(true, Excluded(_)) => 0,
|
||||
};
|
||||
|
||||
@ -1987,9 +1987,9 @@ where
|
||||
}
|
||||
(i, false) => i,
|
||||
},
|
||||
(_, Unbounded) => max_node.keys().len(),
|
||||
(_, Unbounded) => max_node.len(),
|
||||
(true, Included(_)) => 0,
|
||||
(true, Excluded(_)) => max_node.keys().len(),
|
||||
(true, Excluded(_)) => max_node.len(),
|
||||
};
|
||||
|
||||
if !diverged {
|
||||
|
@ -54,10 +54,8 @@ pub const CAPACITY: usize = 2 * B - 1;
|
||||
/// `NodeHeader` because we do not want unnecessary padding between `len` and the keys.
|
||||
/// Crucially, `NodeHeader` can be safely transmuted to different K and V. (This is exploited
|
||||
/// by `as_header`.)
|
||||
/// See `into_key_slice` for an explanation of K2. K2 cannot be safely transmuted around
|
||||
/// because the size of `NodeHeader` depends on its alignment!
|
||||
#[repr(C)]
|
||||
struct NodeHeader<K, V, K2 = ()> {
|
||||
struct NodeHeader<K, V> {
|
||||
/// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`.
|
||||
/// This either points to an actual node or is null.
|
||||
parent: *const InternalNode<K, V>,
|
||||
@ -72,9 +70,6 @@ struct NodeHeader<K, V, K2 = ()> {
|
||||
/// This next to `parent_idx` to encourage the compiler to join `len` and
|
||||
/// `parent_idx` into the same 32-bit word, reducing space overhead.
|
||||
len: u16,
|
||||
|
||||
/// See `into_key_slice`.
|
||||
keys_start: [K2; 0],
|
||||
}
|
||||
#[repr(C)]
|
||||
struct LeafNode<K, V> {
|
||||
@ -128,7 +123,7 @@ unsafe impl Sync for NodeHeader<(), ()> {}
|
||||
// We use just a header in order to save space, since no operation on an empty tree will
|
||||
// ever take a pointer past the first key.
|
||||
static EMPTY_ROOT_NODE: NodeHeader<(), ()> =
|
||||
NodeHeader { parent: ptr::null(), parent_idx: MaybeUninit::uninit(), len: 0, keys_start: [] };
|
||||
NodeHeader { parent: ptr::null(), parent_idx: MaybeUninit::uninit(), len: 0 };
|
||||
|
||||
/// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
|
||||
/// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an
|
||||
@ -390,14 +385,13 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
|
||||
}
|
||||
|
||||
/// Borrows a view into the keys stored in the node.
|
||||
/// Works on all possible nodes, including the shared root.
|
||||
pub fn keys(&self) -> &[K] {
|
||||
/// The caller must ensure that the node is not the shared root.
|
||||
pub unsafe fn keys(&self) -> &[K] {
|
||||
self.reborrow().into_key_slice()
|
||||
}
|
||||
|
||||
/// Borrows a view into the values stored in the node.
|
||||
/// The caller must ensure that the node is not the shared root.
|
||||
/// This function is not public, so doesn't have to support shared roots like `keys` does.
|
||||
fn vals(&self) -> &[V] {
|
||||
self.reborrow().into_val_slice()
|
||||
}
|
||||
@ -515,7 +509,6 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
|
||||
}
|
||||
|
||||
/// The caller must ensure that the node is not the shared root.
|
||||
/// This function is not public, so doesn't have to support shared roots like `keys` does.
|
||||
fn keys_mut(&mut self) -> &mut [K] {
|
||||
unsafe { self.reborrow_mut().into_key_slice_mut() }
|
||||
}
|
||||
@ -527,48 +520,11 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
|
||||
fn into_key_slice(self) -> &'a [K] {
|
||||
// We have to be careful here because we might be pointing to the shared root.
|
||||
// In that case, we must not create an `&LeafNode`. We could just return
|
||||
// an empty slice whenever the length is 0 (this includes the shared root),
|
||||
// but we want to avoid that run-time check.
|
||||
// Instead, we create a slice pointing into the node whenever possible.
|
||||
// We can sometimes do this even for the shared root, as the slice will be
|
||||
// empty and `NodeHeader` contains an empty `keys_start` array.
|
||||
// We cannot *always* do this because:
|
||||
// - `keys_start` is not correctly typed because we want `NodeHeader`'s size to
|
||||
// not depend on the alignment of `K` (needed because `as_header` should be safe).
|
||||
// For this reason, `NodeHeader` has this `K2` parameter (that's usually `()`
|
||||
// and hence just adds a size-0-align-1 field, not affecting layout).
|
||||
// If the correctly typed header is more highly aligned than the allocated header,
|
||||
// we cannot transmute safely.
|
||||
// - Even if we can transmute, the offset of a correctly typed `keys_start` might
|
||||
// be different and outside the bounds of the allocated header!
|
||||
// So we do an alignment check and a size check first, that will be evaluated
|
||||
// at compile-time, and only do any run-time check in the rare case that
|
||||
// the compile-time checks signal danger.
|
||||
if (mem::align_of::<NodeHeader<K, V, K>>() > mem::align_of::<NodeHeader<K, V>>()
|
||||
|| mem::size_of::<NodeHeader<K, V, K>>() != mem::size_of::<NodeHeader<K, V>>())
|
||||
&& self.is_shared_root()
|
||||
{
|
||||
&[]
|
||||
} else {
|
||||
// If we are a `LeafNode<K, V>`, we can always transmute to
|
||||
// `NodeHeader<K, V, K>` and `keys_start` always has the same offset
|
||||
// as the actual `keys`.
|
||||
// Thanks to the checks above, we know that we can transmute to
|
||||
// `NodeHeader<K, V, K>` and that `keys_start` will be
|
||||
// in-bounds of some allocation even if this is the shared root!
|
||||
// (We might be one-past-the-end, but that is allowed by LLVM.)
|
||||
// Thus we can use `NodeHeader<K, V, K>`
|
||||
// to compute the pointer where the keys start.
|
||||
// This entire hack will become unnecessary once
|
||||
// <https://github.com/rust-lang/rfcs/pull/2582> lands, then we can just take a raw
|
||||
// pointer to the `keys` field of `*const InternalNode<K, V>`.
|
||||
let header = self.as_header() as *const _ as *const NodeHeader<K, V, K>;
|
||||
let keys = unsafe { &(*header).keys_start as *const _ as *const K };
|
||||
unsafe { slice::from_raw_parts(keys, self.len()) }
|
||||
}
|
||||
/// The caller must ensure that the node is not the shared root.
|
||||
unsafe fn into_key_slice(self) -> &'a [K] {
|
||||
debug_assert!(!self.is_shared_root());
|
||||
// We cannot be the shared root, so `as_leaf` is okay.
|
||||
slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().keys), self.len())
|
||||
}
|
||||
|
||||
/// The caller must ensure that the node is not the shared root.
|
||||
@ -578,9 +534,10 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
|
||||
unsafe { slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().vals), self.len()) }
|
||||
}
|
||||
|
||||
/// The caller must ensure that the node is not the shared root.
|
||||
fn into_slices(self) -> (&'a [K], &'a [V]) {
|
||||
let k = unsafe { ptr::read(&self) };
|
||||
(k.into_key_slice(), self.into_val_slice())
|
||||
(unsafe { k.into_key_slice() }, self.into_val_slice())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,16 +61,18 @@ where
|
||||
{
|
||||
// This function is defined over all borrow types (immutable, mutable, owned),
|
||||
// and may be called on the shared root in each case.
|
||||
// Crucially, we use `keys()` here, i.e., we work with immutable data.
|
||||
// `keys_mut()` does not support the shared root, so we cannot use it.
|
||||
// Using `keys()` is fine here even if BorrowType is mutable, as all we return
|
||||
// is an index -- not a reference.
|
||||
for (i, k) in node.keys().iter().enumerate() {
|
||||
match key.cmp(k.borrow()) {
|
||||
Ordering::Greater => {}
|
||||
Ordering::Equal => return (i, true),
|
||||
Ordering::Less => return (i, false),
|
||||
let len = node.len();
|
||||
if len > 0 {
|
||||
let keys = unsafe { node.keys() }; // safe because a non-empty node cannot be the shared root
|
||||
for (i, k) in keys.iter().enumerate() {
|
||||
match key.cmp(k.borrow()) {
|
||||
Ordering::Greater => {}
|
||||
Ordering::Equal => return (i, true),
|
||||
Ordering::Less => return (i, false),
|
||||
}
|
||||
}
|
||||
}
|
||||
(node.keys().len(), false)
|
||||
(len, false)
|
||||
}
|
||||
|
@ -337,7 +337,10 @@ impl AutoTraitFinder<'tcx> {
|
||||
&Err(SelectionError::Unimplemented) => {
|
||||
if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) {
|
||||
already_visited.remove(&pred);
|
||||
self.add_user_pred(&mut user_computed_preds, ty::Predicate::Trait(pred));
|
||||
self.add_user_pred(
|
||||
&mut user_computed_preds,
|
||||
ty::Predicate::Trait(pred, ast::Constness::NotConst),
|
||||
);
|
||||
predicates.push_back(pred);
|
||||
} else {
|
||||
debug!(
|
||||
@ -405,7 +408,7 @@ impl AutoTraitFinder<'tcx> {
|
||||
let mut should_add_new = true;
|
||||
user_computed_preds.retain(|&old_pred| {
|
||||
match (&new_pred, old_pred) {
|
||||
(&ty::Predicate::Trait(new_trait), ty::Predicate::Trait(old_trait)) => {
|
||||
(&ty::Predicate::Trait(new_trait, _), ty::Predicate::Trait(old_trait, _)) => {
|
||||
if new_trait.def_id() == old_trait.def_id() {
|
||||
let new_substs = new_trait.skip_binder().trait_ref.substs;
|
||||
let old_substs = old_trait.skip_binder().trait_ref.substs;
|
||||
@ -627,7 +630,7 @@ impl AutoTraitFinder<'tcx> {
|
||||
// We check this by calling is_of_param on the relevant types
|
||||
// from the various possible predicates
|
||||
match &predicate {
|
||||
&ty::Predicate::Trait(p) => {
|
||||
&ty::Predicate::Trait(p, _) => {
|
||||
if self.is_param_no_infer(p.skip_binder().trait_ref.substs)
|
||||
&& !only_projections
|
||||
&& is_new_pred
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::traits::Obligation;
|
||||
use crate::ty::{self, ToPredicate, Ty, TyCtxt};
|
||||
use crate::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
||||
use super::{ChalkFulfillmentContext, FulfillmentContext, FulfillmentError};
|
||||
@ -33,7 +33,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
|
||||
cause,
|
||||
recursion_depth: 0,
|
||||
param_env,
|
||||
predicate: trait_ref.to_predicate(),
|
||||
predicate: trait_ref.without_const().to_predicate(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -19,7 +19,9 @@ use crate::ty::error::ExpectedFound;
|
||||
use crate::ty::fast_reject;
|
||||
use crate::ty::fold::TypeFolder;
|
||||
use crate::ty::SubtypePredicate;
|
||||
use crate::ty::{self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
||||
use crate::ty::{
|
||||
self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
|
||||
};
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
@ -128,7 +130,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
let (cond, error) = match (cond, error) {
|
||||
(&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error)) => (cond, error),
|
||||
(&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error, _)) => (cond, error),
|
||||
_ => {
|
||||
// FIXME: make this work in other cases too.
|
||||
return false;
|
||||
@ -136,7 +138,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
};
|
||||
|
||||
for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) {
|
||||
if let ty::Predicate::Trait(implication) = implication {
|
||||
if let ty::Predicate::Trait(implication, _) = implication {
|
||||
let error = error.to_poly_trait_ref();
|
||||
let implication = implication.to_poly_trait_ref();
|
||||
// FIXME: I'm just not taking associated types at all here.
|
||||
@ -528,7 +530,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
ty::Predicate::Trait(ref trait_predicate, _) => {
|
||||
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
|
||||
|
||||
if self.tcx.sess.has_errors() && trait_predicate.references_error() {
|
||||
@ -581,7 +583,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
"{}",
|
||||
message.unwrap_or_else(|| format!(
|
||||
"the trait bound `{}` is not satisfied{}",
|
||||
trait_ref.to_predicate(),
|
||||
trait_ref.without_const().to_predicate(),
|
||||
post_message,
|
||||
))
|
||||
);
|
||||
@ -693,7 +695,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
trait_pred
|
||||
});
|
||||
let unit_obligation = Obligation {
|
||||
predicate: ty::Predicate::Trait(predicate),
|
||||
predicate: ty::Predicate::Trait(
|
||||
predicate,
|
||||
ast::Constness::NotConst,
|
||||
),
|
||||
..obligation.clone()
|
||||
};
|
||||
if self.predicate_may_hold(&unit_obligation) {
|
||||
@ -986,7 +991,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
) -> PredicateObligation<'tcx> {
|
||||
let new_trait_ref =
|
||||
ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) };
|
||||
Obligation::new(cause, param_env, new_trait_ref.to_predicate())
|
||||
Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1074,7 +1079,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
let mut err = match predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
ty::Predicate::Trait(ref data, _) => {
|
||||
let trait_ref = data.to_poly_trait_ref();
|
||||
let self_ty = trait_ref.self_ty();
|
||||
debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref);
|
||||
@ -1267,8 +1272,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
)
|
||||
.value;
|
||||
|
||||
let obligation =
|
||||
Obligation::new(ObligationCause::dummy(), param_env, cleaned_pred.to_predicate());
|
||||
let obligation = Obligation::new(
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
cleaned_pred.without_const().to_predicate(),
|
||||
);
|
||||
|
||||
self.predicate_may_hold(&obligation)
|
||||
})
|
||||
|
@ -6,7 +6,7 @@ use super::{
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::traits::object_safety::object_safety_violations;
|
||||
use crate::ty::TypeckTables;
|
||||
use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
||||
use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||
|
||||
use rustc_errors::{
|
||||
error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style,
|
||||
@ -48,7 +48,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
} else {
|
||||
" where"
|
||||
},
|
||||
trait_ref.to_predicate(),
|
||||
trait_ref.without_const().to_predicate(),
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
@ -338,8 +338,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty);
|
||||
let substs = self.tcx.mk_substs_trait(new_self_ty, &[]);
|
||||
let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs);
|
||||
let new_obligation =
|
||||
Obligation::new(ObligationCause::dummy(), param_env, new_trait_ref.to_predicate());
|
||||
let new_obligation = Obligation::new(
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
new_trait_ref.without_const().to_predicate(),
|
||||
);
|
||||
if self.predicate_must_hold_modulo_regions(&new_obligation) {
|
||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||
// We have a very specific type of error, where just borrowing this argument
|
||||
@ -1120,7 +1123,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
// the type. The last generator has information about where the bound was introduced. At
|
||||
// least one generator should be present for this diagnostic to be modified.
|
||||
let (mut trait_ref, mut target_ty) = match obligation.predicate {
|
||||
ty::Predicate::Trait(p) => {
|
||||
ty::Predicate::Trait(p, _) => {
|
||||
(Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty()))
|
||||
}
|
||||
_ => (None, None),
|
||||
@ -1543,7 +1546,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
err.note(&format!("required because it appears within the type `{}`", ty));
|
||||
obligated_types.push(ty);
|
||||
|
||||
let parent_predicate = parent_trait_ref.to_predicate();
|
||||
let parent_predicate = parent_trait_ref.without_const().to_predicate();
|
||||
if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
|
||||
self.note_obligation_cause_code(
|
||||
err,
|
||||
@ -1560,7 +1563,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
parent_trait_ref.print_only_trait_path(),
|
||||
parent_trait_ref.skip_binder().self_ty()
|
||||
));
|
||||
let parent_predicate = parent_trait_ref.to_predicate();
|
||||
let parent_predicate = parent_trait_ref.without_const().to_predicate();
|
||||
self.note_obligation_cause_code(
|
||||
err,
|
||||
&parent_predicate,
|
||||
|
@ -311,7 +311,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
||||
}
|
||||
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
ty::Predicate::Trait(ref data, _) => {
|
||||
let trait_obligation = obligation.with(data.clone());
|
||||
|
||||
if data.is_global() {
|
||||
|
@ -29,7 +29,7 @@ use crate::mir::interpret::ErrorHandled;
|
||||
use crate::ty::error::{ExpectedFound, TypeError};
|
||||
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use crate::ty::subst::{InternalSubsts, SubstsRef};
|
||||
use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt};
|
||||
use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use crate::util::common::ErrorReported;
|
||||
use chalk_engine;
|
||||
use rustc_hir as hir;
|
||||
@ -732,7 +732,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
|
||||
param_env,
|
||||
cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID),
|
||||
recursion_depth: 0,
|
||||
predicate: trait_ref.to_predicate(),
|
||||
predicate: trait_ref.without_const().to_predicate(),
|
||||
};
|
||||
|
||||
let result = infcx.predicate_must_hold_modulo_regions(&obligation);
|
||||
|
@ -12,7 +12,7 @@ use super::elaborate_predicates;
|
||||
|
||||
use crate::traits::{self, Obligation, ObligationCause};
|
||||
use crate::ty::subst::{InternalSubsts, Subst};
|
||||
use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
||||
use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
||||
@ -234,7 +234,7 @@ fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_o
|
||||
.map(|(predicate, _)| predicate.subst_supertrait(tcx, &trait_ref))
|
||||
.any(|predicate| {
|
||||
match predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
ty::Predicate::Trait(ref data, _) => {
|
||||
// In the case of a trait predicate, we can skip the "self" type.
|
||||
data.skip_binder().input_types().skip(1).any(has_self_ty)
|
||||
}
|
||||
@ -285,7 +285,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||
let predicates = tcx.predicates_of(def_id);
|
||||
let predicates = predicates.instantiate_identity(tcx).predicates;
|
||||
elaborate_predicates(tcx, predicates).any(|predicate| match predicate {
|
||||
ty::Predicate::Trait(ref trait_pred) => {
|
||||
ty::Predicate::Trait(ref trait_pred, _) => {
|
||||
trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0)
|
||||
}
|
||||
ty::Predicate::Projection(..)
|
||||
@ -585,6 +585,7 @@ fn receiver_is_dispatchable<'tcx>(
|
||||
def_id: unsize_did,
|
||||
substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]),
|
||||
}
|
||||
.without_const()
|
||||
.to_predicate();
|
||||
|
||||
// U: Trait<Arg1, ..., ArgN>
|
||||
@ -598,7 +599,7 @@ fn receiver_is_dispatchable<'tcx>(
|
||||
}
|
||||
});
|
||||
|
||||
ty::TraitRef { def_id: unsize_did, substs }.to_predicate()
|
||||
ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate()
|
||||
};
|
||||
|
||||
let caller_bounds: Vec<Predicate<'tcx>> = param_env
|
||||
@ -620,6 +621,7 @@ fn receiver_is_dispatchable<'tcx>(
|
||||
def_id: dispatch_from_dyn_did,
|
||||
substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
|
||||
}
|
||||
.without_const()
|
||||
.to_predicate();
|
||||
|
||||
Obligation::new(ObligationCause::dummy(), param_env, predicate)
|
||||
|
@ -16,7 +16,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
use crate::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use crate::ty::subst::{InternalSubsts, Subst};
|
||||
use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt};
|
||||
use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::HashStable;
|
||||
@ -738,7 +738,12 @@ fn get_paranoid_cache_value_obligation<'a, 'tcx>(
|
||||
depth: usize,
|
||||
) -> PredicateObligation<'tcx> {
|
||||
let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref();
|
||||
Obligation { cause, recursion_depth: depth, param_env, predicate: trait_ref.to_predicate() }
|
||||
Obligation {
|
||||
cause,
|
||||
recursion_depth: depth,
|
||||
param_env,
|
||||
predicate: trait_ref.without_const().to_predicate(),
|
||||
}
|
||||
}
|
||||
|
||||
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
|
||||
@ -772,7 +777,7 @@ fn normalize_to_error<'a, 'tcx>(
|
||||
cause,
|
||||
recursion_depth: depth,
|
||||
param_env,
|
||||
predicate: trait_ref.to_predicate(),
|
||||
predicate: trait_ref.without_const().to_predicate(),
|
||||
};
|
||||
let tcx = selcx.infcx().tcx;
|
||||
let def_id = projection_ty.item_def_id;
|
||||
|
@ -24,7 +24,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
|
||||
// `&T`, accounts for about 60% percentage of the predicates
|
||||
// we have to prove. No need to canonicalize and all that for
|
||||
// such cases.
|
||||
if let Predicate::Trait(trait_ref) = key.value.predicate {
|
||||
if let Predicate::Trait(trait_ref, _) = key.value.predicate {
|
||||
if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
|
||||
if trait_ref.def_id() == sized_def_id {
|
||||
if trait_ref.skip_binder().self_ty().is_trivially_sized(tcx) {
|
||||
|
@ -37,7 +37,7 @@ use crate::middle::lang_items;
|
||||
use crate::ty::fast_reject;
|
||||
use crate::ty::relate::TypeRelation;
|
||||
use crate::ty::subst::{Subst, SubstsRef};
|
||||
use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
||||
use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
@ -51,7 +51,7 @@ use std::cmp;
|
||||
use std::fmt::{self, Display};
|
||||
use std::iter;
|
||||
use std::rc::Rc;
|
||||
use syntax::attr;
|
||||
use syntax::{ast, attr};
|
||||
|
||||
pub struct SelectionContext<'cx, 'tcx> {
|
||||
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||
@ -718,7 +718,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
|
||||
match obligation.predicate {
|
||||
ty::Predicate::Trait(ref t) => {
|
||||
ty::Predicate::Trait(ref t, _) => {
|
||||
debug_assert!(!t.has_escaping_bound_vars());
|
||||
let obligation = obligation.with(t.clone());
|
||||
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
|
||||
@ -945,7 +945,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// trait refs. This is important because it's only a cycle
|
||||
// if the regions match exactly.
|
||||
let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth);
|
||||
let cycle = cycle.map(|stack| ty::Predicate::Trait(stack.obligation.predicate));
|
||||
let cycle = cycle.map(|stack| {
|
||||
ty::Predicate::Trait(stack.obligation.predicate, ast::Constness::NotConst)
|
||||
});
|
||||
if self.coinductive_match(cycle) {
|
||||
debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref);
|
||||
Some(EvaluatedToOk)
|
||||
@ -1060,7 +1062,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
|
||||
let result = match predicate {
|
||||
ty::Predicate::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()),
|
||||
ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
|
||||
_ => false,
|
||||
};
|
||||
debug!("coinductive_predicate({:?}) = {:?}", predicate, result);
|
||||
@ -3366,7 +3368,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
|
||||
tcx.mk_substs_trait(source, &[]),
|
||||
);
|
||||
nested.push(predicate_to_obligation(tr.to_predicate()));
|
||||
nested.push(predicate_to_obligation(tr.without_const().to_predicate()));
|
||||
|
||||
// If the type is `Foo + 'a`, ensure that the type
|
||||
// being cast to `Foo + 'a` outlives `'a`:
|
||||
|
@ -4,7 +4,7 @@ use smallvec::SmallVec;
|
||||
|
||||
use crate::ty::outlives::Component;
|
||||
use crate::ty::subst::{GenericArg, Subst, SubstsRef};
|
||||
use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt};
|
||||
use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -13,8 +13,8 @@ use super::{Normalized, Obligation, ObligationCause, PredicateObligation, Select
|
||||
|
||||
fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
||||
match *pred {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data))
|
||||
ty::Predicate::Trait(ref data, constness) => {
|
||||
ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness)
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(ref data) => {
|
||||
@ -99,14 +99,14 @@ pub fn elaborate_trait_ref<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
) -> Elaborator<'tcx> {
|
||||
elaborate_predicates(tcx, vec![trait_ref.to_predicate()])
|
||||
elaborate_predicates(tcx, vec![trait_ref.without_const().to_predicate()])
|
||||
}
|
||||
|
||||
pub fn elaborate_trait_refs<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
|
||||
) -> Elaborator<'tcx> {
|
||||
let predicates = trait_refs.map(|trait_ref| trait_ref.to_predicate()).collect();
|
||||
let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate()).collect();
|
||||
elaborate_predicates(tcx, predicates)
|
||||
}
|
||||
|
||||
@ -127,7 +127,7 @@ impl Elaborator<'tcx> {
|
||||
fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) {
|
||||
let tcx = self.visited.tcx;
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
ty::Predicate::Trait(ref data, _) => {
|
||||
// Get predicates declared on the trait.
|
||||
let predicates = tcx.super_predicates_of(data.def_id());
|
||||
|
||||
@ -358,7 +358,7 @@ impl<'tcx> TraitAliasExpander<'tcx> {
|
||||
fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
|
||||
let tcx = self.tcx;
|
||||
let trait_ref = item.trait_ref();
|
||||
let pred = trait_ref.to_predicate();
|
||||
let pred = trait_ref.without_const().to_predicate();
|
||||
|
||||
debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
|
||||
|
||||
@ -370,13 +370,9 @@ impl<'tcx> TraitAliasExpander<'tcx> {
|
||||
|
||||
// Don't recurse if this trait alias is already on the stack for the DFS search.
|
||||
let anon_pred = anonymize_predicate(tcx, &pred);
|
||||
if item
|
||||
.path
|
||||
.iter()
|
||||
.rev()
|
||||
.skip(1)
|
||||
.any(|(tr, _)| anonymize_predicate(tcx, &tr.to_predicate()) == anon_pred)
|
||||
{
|
||||
if item.path.iter().rev().skip(1).any(|(tr, _)| {
|
||||
anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred
|
||||
}) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -471,7 +467,7 @@ impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<
|
||||
|
||||
fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
|
||||
while let Some(pred) = self.base_iterator.next() {
|
||||
if let ty::Predicate::Trait(data) = pred {
|
||||
if let ty::Predicate::Trait(data, _) = pred {
|
||||
return Some(data.to_poly_trait_ref());
|
||||
}
|
||||
}
|
||||
@ -545,7 +541,12 @@ pub fn predicate_for_trait_ref<'tcx>(
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
recursion_depth: usize,
|
||||
) -> PredicateObligation<'tcx> {
|
||||
Obligation { cause, param_env, recursion_depth, predicate: trait_ref.to_predicate() }
|
||||
Obligation {
|
||||
cause,
|
||||
param_env,
|
||||
recursion_depth,
|
||||
predicate: trait_ref.without_const().to_predicate(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn predicate_for_trait_def(
|
||||
|
@ -3,7 +3,7 @@ use crate::infer::InferCtxt;
|
||||
use crate::middle::lang_items;
|
||||
use crate::traits::{self, AssocTypeBoundData};
|
||||
use crate::ty::subst::SubstsRef;
|
||||
use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
||||
use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
@ -62,7 +62,7 @@ pub fn predicate_obligations<'a, 'tcx>(
|
||||
|
||||
// (*) ok to skip binders, because wf code is prepared for it
|
||||
match *predicate {
|
||||
ty::Predicate::Trait(ref t) => {
|
||||
ty::Predicate::Trait(ref t, _) => {
|
||||
wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*)
|
||||
}
|
||||
ty::Predicate::RegionOutlives(..) => {}
|
||||
@ -245,7 +245,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::Predicate::Trait(proj) => {
|
||||
ty::Predicate::Trait(proj, _) => {
|
||||
// An associated item obligation born out of the `trait` failed to be met.
|
||||
// Point at the `impl` that failed the obligation, the associated item that
|
||||
// needed to meet the obligation, and the definition of that associated item,
|
||||
@ -350,7 +350,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
self.compute_trait_ref(&trait_ref, Elaborate::None);
|
||||
|
||||
if !data.has_escaping_bound_vars() {
|
||||
let predicate = trait_ref.to_predicate();
|
||||
let predicate = trait_ref.without_const().to_predicate();
|
||||
let cause = self.cause(traits::ProjectionWf(data));
|
||||
self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
|
||||
}
|
||||
@ -378,7 +378,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
||||
def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None),
|
||||
substs: self.infcx.tcx.mk_substs_trait(subty, &[]),
|
||||
};
|
||||
self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate()));
|
||||
self.out.push(traits::Obligation::new(
|
||||
cause,
|
||||
self.param_env,
|
||||
trait_ref.without_const().to_predicate(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,6 +150,15 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeFoldable<'tcx> for syntax::ast::Constness {
|
||||
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
|
||||
*self
|
||||
}
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// The `TypeFolder` trait defines the actual *folding*. There is a
|
||||
/// method defined for every foldable type. Each of these has a
|
||||
/// default implementation that does an "identity" fold. Within each
|
||||
|
@ -52,7 +52,7 @@ use std::ops::Deref;
|
||||
use std::ops::Range;
|
||||
use std::slice;
|
||||
use std::{mem, ptr};
|
||||
use syntax::ast::{self, Ident, Name, NodeId};
|
||||
use syntax::ast::{self, Constness, Ident, Name, NodeId};
|
||||
use syntax::attr;
|
||||
|
||||
pub use self::sty::BoundRegion::*;
|
||||
@ -1068,7 +1068,11 @@ pub enum Predicate<'tcx> {
|
||||
/// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
|
||||
/// the `Self` type of the trait reference and `A`, `B`, and `C`
|
||||
/// would be the type parameters.
|
||||
Trait(PolyTraitPredicate<'tcx>),
|
||||
///
|
||||
/// A trait predicate will have `Constness::Const` if it originates
|
||||
/// from a bound on a `const fn` without the `?const` opt-out (e.g.,
|
||||
/// `const fn foobar<Foo: Bar>() {}`).
|
||||
Trait(PolyTraitPredicate<'tcx>, Constness),
|
||||
|
||||
/// `where 'a: 'b`
|
||||
RegionOutlives(PolyRegionOutlivesPredicate<'tcx>),
|
||||
@ -1191,8 +1195,8 @@ impl<'tcx> Predicate<'tcx> {
|
||||
|
||||
let substs = &trait_ref.skip_binder().substs;
|
||||
match *self {
|
||||
Predicate::Trait(ref binder) => {
|
||||
Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs)))
|
||||
Predicate::Trait(ref binder, constness) => {
|
||||
Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs)), constness)
|
||||
}
|
||||
Predicate::Subtype(ref binder) => {
|
||||
Predicate::Subtype(binder.map_bound(|data| data.subst(tcx, substs)))
|
||||
@ -1336,15 +1340,33 @@ pub trait ToPredicate<'tcx> {
|
||||
fn to_predicate(&self) -> Predicate<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
|
||||
impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> {
|
||||
fn to_predicate(&self) -> Predicate<'tcx> {
|
||||
ty::Predicate::Trait(ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.clone() }))
|
||||
ty::Predicate::Trait(
|
||||
ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }),
|
||||
self.constness,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> {
|
||||
impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&TraitRef<'tcx>> {
|
||||
fn to_predicate(&self) -> Predicate<'tcx> {
|
||||
ty::Predicate::Trait(self.to_poly_trait_predicate())
|
||||
ty::Predicate::Trait(
|
||||
ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.value.clone() }),
|
||||
self.constness,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
|
||||
fn to_predicate(&self) -> Predicate<'tcx> {
|
||||
ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<&PolyTraitRef<'tcx>> {
|
||||
fn to_predicate(&self) -> Predicate<'tcx> {
|
||||
ty::Predicate::Trait(self.value.to_poly_trait_predicate(), self.constness)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1413,7 +1435,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||
/// with depth 0 are bound by the predicate.
|
||||
pub fn walk_tys(&'a self) -> impl Iterator<Item = Ty<'tcx>> + 'a {
|
||||
match *self {
|
||||
ty::Predicate::Trait(ref data) => {
|
||||
ty::Predicate::Trait(ref data, _) => {
|
||||
WalkTysIter::InputTypes(data.skip_binder().input_types())
|
||||
}
|
||||
ty::Predicate::Subtype(binder) => {
|
||||
@ -1439,7 +1461,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||
|
||||
pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'tcx>> {
|
||||
match *self {
|
||||
Predicate::Trait(ref t) => Some(t.to_poly_trait_ref()),
|
||||
Predicate::Trait(ref t, _) => Some(t.to_poly_trait_ref()),
|
||||
Predicate::Projection(..)
|
||||
| Predicate::Subtype(..)
|
||||
| Predicate::RegionOutlives(..)
|
||||
@ -1700,6 +1722,33 @@ impl<'tcx> ParamEnv<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ConstnessAnd<T> {
|
||||
pub constness: Constness,
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
// FIXME(ecstaticmorse): Audit all occurrences of `without_const().to_predicate()` to ensure that
|
||||
// the constness of trait bounds is being propagated correctly.
|
||||
pub trait WithConstness: Sized {
|
||||
#[inline]
|
||||
fn with_constness(self, constness: Constness) -> ConstnessAnd<Self> {
|
||||
ConstnessAnd { constness, value: self }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_const(self) -> ConstnessAnd<Self> {
|
||||
self.with_constness(Constness::Const)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn without_const(self) -> ConstnessAnd<Self> {
|
||||
self.with_constness(Constness::NotConst)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> WithConstness for T {}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
|
||||
pub struct ParamEnvAnd<'tcx, T> {
|
||||
pub param_env: ParamEnv<'tcx>,
|
||||
|
@ -1791,7 +1791,12 @@ define_print_and_forward_display! {
|
||||
|
||||
ty::Predicate<'tcx> {
|
||||
match *self {
|
||||
ty::Predicate::Trait(ref data) => p!(print(data)),
|
||||
ty::Predicate::Trait(ref data, constness) => {
|
||||
if let ast::Constness::Const = constness {
|
||||
p!(write("const "));
|
||||
}
|
||||
p!(print(data))
|
||||
}
|
||||
ty::Predicate::Subtype(ref predicate) => p!(print(predicate)),
|
||||
ty::Predicate::RegionOutlives(ref predicate) => p!(print(predicate)),
|
||||
ty::Predicate::TypeOutlives(ref predicate) => p!(print(predicate)),
|
||||
|
@ -15,6 +15,7 @@ use smallvec::SmallVec;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use syntax::ast;
|
||||
|
||||
impl fmt::Debug for ty::GenericParamDef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
@ -234,7 +235,12 @@ impl fmt::Debug for ty::ProjectionPredicate<'tcx> {
|
||||
impl fmt::Debug for ty::Predicate<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ty::Predicate::Trait(ref a) => a.fmt(f),
|
||||
ty::Predicate::Trait(ref a, constness) => {
|
||||
if let ast::Constness::Const = constness {
|
||||
write!(f, "const ")?;
|
||||
}
|
||||
a.fmt(f)
|
||||
}
|
||||
ty::Predicate::Subtype(ref pair) => pair.fmt(f),
|
||||
ty::Predicate::RegionOutlives(ref pair) => pair.fmt(f),
|
||||
ty::Predicate::TypeOutlives(ref pair) => pair.fmt(f),
|
||||
@ -474,7 +480,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> {
|
||||
type Lifted = ty::Predicate<'tcx>;
|
||||
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
match *self {
|
||||
ty::Predicate::Trait(ref binder) => tcx.lift(binder).map(ty::Predicate::Trait),
|
||||
ty::Predicate::Trait(ref binder, constness) => {
|
||||
tcx.lift(binder).map(|binder| ty::Predicate::Trait(binder, constness))
|
||||
}
|
||||
ty::Predicate::Subtype(ref binder) => tcx.lift(binder).map(ty::Predicate::Subtype),
|
||||
ty::Predicate::RegionOutlives(ref binder) => {
|
||||
tcx.lift(binder).map(ty::Predicate::RegionOutlives)
|
||||
|
@ -12,7 +12,9 @@ use crate::mir::interpret::Scalar;
|
||||
use crate::mir::Promoted;
|
||||
use crate::ty::layout::VariantIdx;
|
||||
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
|
||||
use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
|
||||
use crate::ty::{
|
||||
self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness,
|
||||
};
|
||||
use crate::ty::{List, ParamEnv, ParamEnvAnd, TyS};
|
||||
use polonius_engine::Atom;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
@ -665,14 +667,16 @@ impl<'tcx> Binder<ExistentialPredicate<'tcx>> {
|
||||
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> {
|
||||
use crate::ty::ToPredicate;
|
||||
match *self.skip_binder() {
|
||||
ExistentialPredicate::Trait(tr) => Binder(tr).with_self_ty(tcx, self_ty).to_predicate(),
|
||||
ExistentialPredicate::Trait(tr) => {
|
||||
Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate()
|
||||
}
|
||||
ExistentialPredicate::Projection(p) => {
|
||||
ty::Predicate::Projection(Binder(p.with_self_ty(tcx, self_ty)))
|
||||
}
|
||||
ExistentialPredicate::AutoTrait(did) => {
|
||||
let trait_ref =
|
||||
Binder(ty::TraitRef { def_id: did, substs: tcx.mk_substs_trait(self_ty, &[]) });
|
||||
trait_ref.to_predicate()
|
||||
trait_ref.without_const().to_predicate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -848,10 +848,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
fn with_catch_scope<T, F>(&mut self, catch_id: NodeId, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
{
|
||||
fn with_catch_scope<T>(&mut self, catch_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let len = self.catch_scopes.len();
|
||||
self.catch_scopes.push(catch_id);
|
||||
|
||||
@ -867,10 +864,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
result
|
||||
}
|
||||
|
||||
fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
{
|
||||
fn with_loop_scope<T>(&mut self, loop_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
// We're no longer in the base loop's condition; we're in another loop.
|
||||
let was_in_loop_condition = self.is_in_loop_condition;
|
||||
self.is_in_loop_condition = false;
|
||||
@ -892,10 +886,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
result
|
||||
}
|
||||
|
||||
fn with_loop_condition_scope<T, F>(&mut self, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
{
|
||||
fn with_loop_condition_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let was_in_loop_condition = self.is_in_loop_condition;
|
||||
self.is_in_loop_condition = true;
|
||||
|
||||
|
@ -66,9 +66,8 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
|
||||
if let Some(hir_id) = item_hir_id {
|
||||
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
|
||||
let this = &mut ItemLowerer { lctx: this };
|
||||
if let ItemKind::Impl { ref of_trait, .. } = item.kind {
|
||||
if of_trait.as_ref().map(|tr| tr.constness.is_some()).unwrap_or(false) {
|
||||
this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
|
||||
if let ItemKind::Impl { constness, ref of_trait, .. } = item.kind {
|
||||
if constness == Constness::Const {
|
||||
this.lctx
|
||||
.diagnostic()
|
||||
.span_err(item.span, "const trait impls are not yet implemented");
|
||||
@ -365,6 +364,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
generics: ref ast_generics,
|
||||
of_trait: ref trait_ref,
|
||||
self_ty: ref ty,
|
||||
@ -421,6 +421,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness: self.lower_defaultness(defaultness, true /* [1] */),
|
||||
constness,
|
||||
generics,
|
||||
of_trait: trait_ref,
|
||||
self_ty: lowered_ty,
|
||||
|
@ -1249,10 +1249,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
let bounds =
|
||||
this.arena.alloc_from_iter(bounds.iter().filter_map(
|
||||
|bound| match *bound {
|
||||
GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
|
||||
GenericBound::Trait(ref ty, TraitBoundModifier::None)
|
||||
| GenericBound::Trait(ref ty, TraitBoundModifier::MaybeConst) => {
|
||||
Some(this.lower_poly_trait_ref(ty, itctx.reborrow()))
|
||||
}
|
||||
GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
|
||||
// `?const ?Bound` will cause an error during AST validation
|
||||
// anyways, so treat it like `?Bound` as compilation proceeds.
|
||||
GenericBound::Trait(_, TraitBoundModifier::Maybe)
|
||||
| GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
|
||||
None
|
||||
}
|
||||
GenericBound::Outlives(ref lifetime) => {
|
||||
if lifetime_bound.is_none() {
|
||||
lifetime_bound = Some(this.lower_lifetime(lifetime));
|
||||
@ -2157,10 +2163,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
p: &PolyTraitRef,
|
||||
mut itctx: ImplTraitContext<'_, 'hir>,
|
||||
) -> hir::PolyTraitRef<'hir> {
|
||||
if p.trait_ref.constness.is_some() {
|
||||
self.diagnostic().span_err(p.span, "`?const` on trait bounds is not yet implemented");
|
||||
}
|
||||
|
||||
let bound_generic_params = self.lower_generic_params(
|
||||
&p.bound_generic_params,
|
||||
&NodeMap::default(),
|
||||
@ -2299,7 +2301,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier {
|
||||
match f {
|
||||
TraitBoundModifier::None => hir::TraitBoundModifier::None,
|
||||
TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
|
||||
TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst,
|
||||
|
||||
// `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a
|
||||
// placeholder for compilation to proceed.
|
||||
TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
|
||||
hir::TraitBoundModifier::Maybe
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -614,6 +614,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness: _,
|
||||
constness: _,
|
||||
generics: _,
|
||||
of_trait: Some(_),
|
||||
ref self_ty,
|
||||
@ -647,6 +648,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
generics: _,
|
||||
of_trait: None,
|
||||
self_ty: _,
|
||||
@ -674,6 +676,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
.note("only trait implementations may be annotated with default")
|
||||
.emit();
|
||||
}
|
||||
if constness == Constness::Const {
|
||||
self.err_handler()
|
||||
.struct_span_err(item.span, "inherent impls cannot be `const`")
|
||||
.note("only trait implementations may be annotated with `const`")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
ItemKind::Fn(ref sig, ref generics, _) => {
|
||||
self.visit_fn_header(&sig.header);
|
||||
@ -907,23 +915,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
|
||||
fn visit_param_bound(&mut self, bound: &'a GenericBound) {
|
||||
if let GenericBound::Trait(poly, maybe_bound) = bound {
|
||||
match poly.trait_ref.constness {
|
||||
Some(Constness::NotConst) => {
|
||||
if *maybe_bound == TraitBoundModifier::Maybe {
|
||||
self.err_handler()
|
||||
.span_err(bound.span(), "`?const` and `?` are mutually exclusive");
|
||||
}
|
||||
|
||||
if let Some(ctx) = self.bound_context {
|
||||
let msg = format!("`?const` is not permitted in {}", ctx.description());
|
||||
self.err_handler().span_err(bound.span(), &msg);
|
||||
}
|
||||
match bound {
|
||||
GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
|
||||
if let Some(ctx) = self.bound_context {
|
||||
let msg = format!("`?const` is not permitted in {}", ctx.description());
|
||||
self.err_handler().span_err(bound.span(), &msg);
|
||||
}
|
||||
|
||||
Some(Constness::Const) => panic!("Parser should reject bare `const` on bounds"),
|
||||
None => {}
|
||||
}
|
||||
|
||||
GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
|
||||
self.err_handler()
|
||||
.span_err(bound.span(), "`?const` and `?` are mutually exclusive");
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
||||
visit::walk_param_bound(self, bound)
|
||||
|
@ -709,6 +709,7 @@ impl<'a> TraitDef<'a> {
|
||||
unsafety,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: ast::Constness::NotConst,
|
||||
generics: trait_generics,
|
||||
of_trait: opt_trait_ref,
|
||||
self_ty: self_type,
|
||||
|
@ -160,6 +160,7 @@ fn inject_impl_of_structural_trait(
|
||||
unsafety: ast::Unsafety::Normal,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: ast::Constness::NotConst,
|
||||
generics,
|
||||
of_trait: Some(trait_ref),
|
||||
self_ty: self_type,
|
||||
|
@ -58,9 +58,10 @@ unsafe fn configure_llvm(sess: &Session) {
|
||||
|
||||
let cg_opts = sess.opts.cg.llvm_args.iter();
|
||||
let tg_opts = sess.target.target.options.llvm_args.iter();
|
||||
let sess_args = cg_opts.chain(tg_opts);
|
||||
|
||||
let user_specified_args: FxHashSet<_> =
|
||||
cg_opts.chain(tg_opts).map(|s| llvm_arg_to_arg_name(s)).filter(|s| s.len() > 0).collect();
|
||||
sess_args.clone().map(|s| llvm_arg_to_arg_name(s)).filter(|s| s.len() > 0).collect();
|
||||
|
||||
{
|
||||
// This adds the given argument to LLVM. Unless `force` is true
|
||||
@ -107,7 +108,7 @@ unsafe fn configure_llvm(sess: &Session) {
|
||||
// during inlining. Unfortunately these may block other optimizations.
|
||||
add("-preserve-alignment-assumptions-during-inlining=false", false);
|
||||
|
||||
for arg in &sess.opts.cg.llvm_args {
|
||||
for arg in sess_args {
|
||||
add(&(*arg), true);
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
}
|
||||
|
||||
pub fn trait_ref(&self, path: ast::Path) -> ast::TraitRef {
|
||||
ast::TraitRef { path, constness: None, ref_id: ast::DUMMY_NODE_ID }
|
||||
ast::TraitRef { path, ref_id: ast::DUMMY_NODE_ID }
|
||||
}
|
||||
|
||||
pub fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef {
|
||||
|
@ -364,6 +364,7 @@ impl GenericArgs<'_> {
|
||||
pub enum TraitBoundModifier {
|
||||
None,
|
||||
Maybe,
|
||||
MaybeConst,
|
||||
}
|
||||
|
||||
/// The AST represents all type param bounds as types.
|
||||
@ -2440,6 +2441,7 @@ pub enum ItemKind<'hir> {
|
||||
unsafety: Unsafety,
|
||||
polarity: ImplPolarity,
|
||||
defaultness: Defaultness,
|
||||
constness: Constness,
|
||||
generics: Generics<'hir>,
|
||||
|
||||
/// The trait being implemented, if any.
|
||||
|
@ -570,6 +570,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
|
||||
unsafety: _,
|
||||
defaultness: _,
|
||||
polarity: _,
|
||||
constness: _,
|
||||
ref generics,
|
||||
ref of_trait,
|
||||
ref self_ty,
|
||||
|
@ -631,6 +631,7 @@ impl<'a> State<'a> {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
ref generics,
|
||||
ref of_trait,
|
||||
ref self_ty,
|
||||
@ -647,6 +648,10 @@ impl<'a> State<'a> {
|
||||
self.s.space();
|
||||
}
|
||||
|
||||
if constness == ast::Constness::Const {
|
||||
self.word_nbsp("const");
|
||||
}
|
||||
|
||||
if let hir::ImplPolarity::Negative = polarity {
|
||||
self.s.word("!");
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
|
||||
ty::Opaque(def, _) => {
|
||||
let mut has_emitted = false;
|
||||
for (predicate, _) in cx.tcx.predicates_of(def).predicates {
|
||||
if let ty::Predicate::Trait(ref poly_trait_predicate) = predicate {
|
||||
if let ty::Predicate::Trait(ref poly_trait_predicate, _) = predicate {
|
||||
let trait_ref = poly_trait_predicate.skip_binder().trait_ref;
|
||||
let def_id = trait_ref.def_id;
|
||||
let descr_pre =
|
||||
|
@ -32,6 +32,7 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use syntax::ast;
|
||||
|
||||
use crate::dataflow::move_paths::MoveData;
|
||||
use crate::dataflow::FlowAtLocation;
|
||||
@ -1930,12 +1931,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
traits::ObligationCauseCode::RepeatVec(should_suggest),
|
||||
),
|
||||
self.param_env,
|
||||
ty::Predicate::Trait(ty::Binder::bind(ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef::new(
|
||||
self.tcx().lang_items().copy_trait().unwrap(),
|
||||
tcx.mk_substs_trait(ty, &[]),
|
||||
),
|
||||
})),
|
||||
ty::Predicate::Trait(
|
||||
ty::Binder::bind(ty::TraitPredicate {
|
||||
trait_ref: ty::TraitRef::new(
|
||||
self.tcx().lang_items().copy_trait().unwrap(),
|
||||
tcx.mk_substs_trait(ty, &[]),
|
||||
),
|
||||
}),
|
||||
ast::Constness::NotConst,
|
||||
),
|
||||
),
|
||||
&traits::SelectionError::Unimplemented,
|
||||
false,
|
||||
@ -2573,7 +2577,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
category: ConstraintCategory,
|
||||
) {
|
||||
self.prove_predicates(
|
||||
Some(ty::Predicate::Trait(trait_ref.to_poly_trait_ref().to_poly_trait_predicate())),
|
||||
Some(ty::Predicate::Trait(
|
||||
trait_ref.to_poly_trait_ref().to_poly_trait_predicate(),
|
||||
ast::Constness::NotConst,
|
||||
)),
|
||||
locations,
|
||||
category,
|
||||
);
|
||||
|
@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use std::borrow::Cow;
|
||||
use syntax::attr;
|
||||
use syntax::{ast, attr};
|
||||
|
||||
type McfResult = Result<(), (Span, Cow<'static, str>)>;
|
||||
|
||||
@ -27,12 +27,19 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -
|
||||
bug!("closure kind predicate on function: {:#?}", predicate)
|
||||
}
|
||||
Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
|
||||
Predicate::Trait(pred) => {
|
||||
Predicate::Trait(pred, constness) => {
|
||||
if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
|
||||
continue;
|
||||
}
|
||||
match pred.skip_binder().self_ty().kind {
|
||||
ty::Param(ref p) => {
|
||||
// Allow `T: ?const Trait`
|
||||
if *constness == ast::Constness::NotConst
|
||||
&& feature_allowed(tcx, def_id, sym::const_trait_bound_opt_out)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let generics = tcx.generics_of(current);
|
||||
let def = generics.type_param(p, tcx);
|
||||
let span = tcx.def_span(def.def_id);
|
||||
|
@ -21,6 +21,7 @@ rustc_errors = { path = "../librustc_errors" }
|
||||
rustc_hir = { path = "../librustc_hir" }
|
||||
rustc_macros = { path = "../librustc_macros" }
|
||||
rustc_serialize = { path = "../libserialize", package = "serialize" }
|
||||
rustc_session = { path = "../librustc_session" }
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
|
@ -582,15 +582,12 @@ crate struct MatchCheckCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
|
||||
crate fn create_and_enter<F, R>(
|
||||
crate fn create_and_enter<R>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
module: DefId,
|
||||
f: F,
|
||||
) -> R
|
||||
where
|
||||
F: for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R,
|
||||
{
|
||||
f: impl for<'b> FnOnce(MatchCheckCtxt<'b, 'tcx>) -> R,
|
||||
) -> R {
|
||||
let pattern_arena = TypedArena::default();
|
||||
|
||||
f(MatchCheckCtxt { tcx, param_env, module, pattern_arena: &pattern_arena })
|
||||
|
@ -5,9 +5,6 @@ use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack}
|
||||
use super::{PatCtxt, PatKind, PatternError};
|
||||
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::lint;
|
||||
use rustc::session::parse::feature_err;
|
||||
use rustc::session::Session;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
@ -15,6 +12,10 @@ use rustc_hir::def::*;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{HirId, Pat};
|
||||
use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
|
||||
use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{MultiSpan, Span};
|
||||
use syntax::ast::Mutability;
|
||||
@ -67,18 +68,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
|
||||
hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
|
||||
};
|
||||
self.check_irrefutable(&loc.pat, msg, sp);
|
||||
|
||||
// Check legality of move bindings and `@` patterns.
|
||||
self.check_patterns(false, &loc.pat);
|
||||
}
|
||||
|
||||
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
|
||||
intravisit::walk_body(self, body);
|
||||
|
||||
for param in body.params {
|
||||
self.check_irrefutable(¶m.pat, "function argument", None);
|
||||
self.check_patterns(false, ¶m.pat);
|
||||
}
|
||||
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
|
||||
intravisit::walk_param(self, param);
|
||||
self.check_irrefutable(¶m.pat, "function argument", None);
|
||||
self.check_patterns(false, ¶m.pat);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,6 +119,25 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
if !self.tcx.features().bindings_after_at {
|
||||
check_legality_of_bindings_in_at_patterns(self, pat);
|
||||
}
|
||||
check_for_bindings_named_same_as_variants(self, pat);
|
||||
}
|
||||
|
||||
fn lower_pattern<'p>(
|
||||
&self,
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
pat: &'tcx hir::Pat<'tcx>,
|
||||
have_errors: &mut bool,
|
||||
) -> (&'p super::Pat<'tcx>, Ty<'tcx>) {
|
||||
let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
|
||||
patcx.include_lint_checks();
|
||||
let pattern = patcx.lower_pattern(pat);
|
||||
let pattern_ty = pattern.ty;
|
||||
let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
|
||||
if !patcx.errors.is_empty() {
|
||||
*have_errors = true;
|
||||
patcx.report_inlining_errors(pat.span);
|
||||
}
|
||||
(pattern, pattern_ty)
|
||||
}
|
||||
|
||||
fn check_match(
|
||||
@ -132,11 +147,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
source: hir::MatchSource,
|
||||
) {
|
||||
for arm in arms {
|
||||
// First, check legality of move bindings.
|
||||
// Check the arm for some things unrelated to exhaustiveness.
|
||||
self.check_patterns(arm.guard.is_some(), &arm.pat);
|
||||
|
||||
// Second, perform some lints.
|
||||
check_for_bindings_named_same_as_variants(self, &arm.pat);
|
||||
}
|
||||
|
||||
let module = self.tcx.hir().get_module_parent(scrut.hir_id);
|
||||
@ -145,16 +157,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
|
||||
let inlined_arms: Vec<_> = arms
|
||||
.iter()
|
||||
.map(|arm| {
|
||||
let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
|
||||
patcx.include_lint_checks();
|
||||
let pattern = patcx.lower_pattern(&arm.pat);
|
||||
let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
|
||||
if !patcx.errors.is_empty() {
|
||||
patcx.report_inlining_errors(arm.pat.span);
|
||||
have_errors = true;
|
||||
}
|
||||
(pattern, &*arm.pat, arm.guard.is_some())
|
||||
.map(|hir::Arm { pat, guard, .. }| {
|
||||
(self.lower_pattern(cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some())
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -178,11 +182,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
||||
fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) {
|
||||
let module = self.tcx.hir().get_module_parent(pat.hir_id);
|
||||
MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |ref mut cx| {
|
||||
let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.tables);
|
||||
patcx.include_lint_checks();
|
||||
let pattern = patcx.lower_pattern(pat);
|
||||
let pattern_ty = pattern.ty;
|
||||
let pattern = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
|
||||
let (pattern, pattern_ty) = self.lower_pattern(cx, pat, &mut false);
|
||||
let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
|
||||
|
||||
let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
|
||||
@ -285,7 +285,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
|
||||
let ty_path = cx.tcx.def_path_str(edef.did);
|
||||
cx.tcx
|
||||
.struct_span_lint_hir(
|
||||
lint::builtin::BINDINGS_WITH_VARIANT_NAME,
|
||||
BINDINGS_WITH_VARIANT_NAME,
|
||||
p.hir_id,
|
||||
p.span,
|
||||
&format!(
|
||||
@ -310,79 +310,63 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
|
||||
}
|
||||
|
||||
/// Checks for common cases of "catchall" patterns that may not be intended as such.
|
||||
fn pat_is_catchall(pat: &Pat<'_>) -> bool {
|
||||
match pat.kind {
|
||||
hir::PatKind::Binding(.., None) => true,
|
||||
hir::PatKind::Binding(.., Some(ref s)) => pat_is_catchall(s),
|
||||
hir::PatKind::Ref(ref s, _) => pat_is_catchall(s),
|
||||
hir::PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(&p)),
|
||||
fn pat_is_catchall(pat: &super::Pat<'_>) -> bool {
|
||||
use super::PatKind::*;
|
||||
match &*pat.kind {
|
||||
Binding { subpattern: None, .. } => true,
|
||||
Binding { subpattern: Some(s), .. } | Deref { subpattern: s } => pat_is_catchall(s),
|
||||
Leaf { subpatterns: s } => s.iter().all(|p| pat_is_catchall(&p.pattern)),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
|
||||
let mut err = tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern");
|
||||
if let Some(catchall) = catchall {
|
||||
// We had a catchall pattern, hint at that.
|
||||
err.span_label(span, "unreachable pattern");
|
||||
err.span_label(catchall, "matches any value");
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
|
||||
let msg = match source {
|
||||
hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
|
||||
hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
|
||||
_ => bug!(),
|
||||
};
|
||||
tcx.lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, msg);
|
||||
}
|
||||
|
||||
/// Check for unreachable patterns.
|
||||
fn check_arms<'p, 'tcx>(
|
||||
cx: &mut MatchCheckCtxt<'p, 'tcx>,
|
||||
arms: &[(&'p super::Pat<'tcx>, &hir::Pat<'_>, bool)],
|
||||
arms: &[(&'p super::Pat<'tcx>, HirId, bool)],
|
||||
source: hir::MatchSource,
|
||||
) -> Matrix<'p, 'tcx> {
|
||||
let mut seen = Matrix::empty();
|
||||
let mut catchall = None;
|
||||
for (arm_index, (pat, hir_pat, has_guard)) in arms.iter().enumerate() {
|
||||
for (arm_index, (pat, id, has_guard)) in arms.iter().copied().enumerate() {
|
||||
let v = PatStack::from_pattern(pat);
|
||||
|
||||
match is_useful(cx, &seen, &v, LeaveOutWitness, hir_pat.hir_id, true) {
|
||||
match is_useful(cx, &seen, &v, LeaveOutWitness, id, true) {
|
||||
NotUseful => {
|
||||
match source {
|
||||
hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
|
||||
|
||||
hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
|
||||
// check which arm we're on.
|
||||
// Check which arm we're on.
|
||||
match arm_index {
|
||||
// The arm with the user-specified pattern.
|
||||
0 => {
|
||||
cx.tcx.lint_hir(
|
||||
lint::builtin::UNREACHABLE_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
"unreachable pattern",
|
||||
);
|
||||
}
|
||||
0 => unreachable_pattern(cx.tcx, pat.span, id, None),
|
||||
// The arm with the wildcard pattern.
|
||||
1 => {
|
||||
let msg = match source {
|
||||
hir::MatchSource::IfLetDesugar { .. } => {
|
||||
"irrefutable if-let pattern"
|
||||
}
|
||||
hir::MatchSource::WhileLetDesugar => {
|
||||
"irrefutable while-let pattern"
|
||||
}
|
||||
_ => bug!(),
|
||||
};
|
||||
cx.tcx.lint_hir(
|
||||
lint::builtin::IRREFUTABLE_LET_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
msg,
|
||||
);
|
||||
}
|
||||
1 => irrefutable_let_pattern(cx.tcx, pat.span, id, source),
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
|
||||
let mut err = cx.tcx.struct_span_lint_hir(
|
||||
lint::builtin::UNREACHABLE_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
"unreachable pattern",
|
||||
);
|
||||
// if we had a catchall pattern, hint at that
|
||||
if let Some(catchall) = catchall {
|
||||
err.span_label(pat.span, "unreachable pattern");
|
||||
err.span_label(catchall, "matches any value");
|
||||
}
|
||||
err.emit();
|
||||
unreachable_pattern(cx.tcx, pat.span, id, catchall);
|
||||
}
|
||||
|
||||
// Unreachable patterns in try and await expressions occur when one of
|
||||
@ -392,19 +376,14 @@ fn check_arms<'p, 'tcx>(
|
||||
}
|
||||
Useful(unreachable_subpatterns) => {
|
||||
for pat in unreachable_subpatterns {
|
||||
cx.tcx.lint_hir(
|
||||
lint::builtin::UNREACHABLE_PATTERNS,
|
||||
hir_pat.hir_id,
|
||||
pat.span,
|
||||
"unreachable pattern",
|
||||
);
|
||||
unreachable_pattern(cx.tcx, pat.span, id, None);
|
||||
}
|
||||
}
|
||||
UsefulWithWitness(_) => bug!(),
|
||||
}
|
||||
if !has_guard {
|
||||
seen.push(v);
|
||||
if catchall.is_none() && pat_is_catchall(hir_pat) {
|
||||
if catchall.is_none() && pat_is_catchall(pat) {
|
||||
catchall = Some(pat.span);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use super::{FollowedByType, Parser, PathStyle};
|
||||
use crate::maybe_whole;
|
||||
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey};
|
||||
use rustc_span::source_map::{self, respan, Span, Spanned};
|
||||
use rustc_span::source_map::{self, respan, Span};
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::BytePos;
|
||||
use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID};
|
||||
@ -565,9 +565,9 @@ impl<'a> Parser<'a> {
|
||||
let constness = if self.eat_keyword(kw::Const) {
|
||||
let span = self.prev_span;
|
||||
self.sess.gated_spans.gate(sym::const_trait_impl, span);
|
||||
Some(respan(span, Constness::Const))
|
||||
Constness::Const
|
||||
} else {
|
||||
None
|
||||
Constness::NotConst
|
||||
};
|
||||
|
||||
// Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
|
||||
@ -630,13 +630,13 @@ impl<'a> Parser<'a> {
|
||||
err_path(ty_first.span)
|
||||
}
|
||||
};
|
||||
let constness = constness.map(|c| c.node);
|
||||
let trait_ref = TraitRef { path, constness, ref_id: ty_first.id };
|
||||
let trait_ref = TraitRef { path, ref_id: ty_first.id };
|
||||
|
||||
ItemKind::Impl {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
generics,
|
||||
of_trait: Some(trait_ref),
|
||||
self_ty: ty_second,
|
||||
@ -644,18 +644,12 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Reject `impl const Type {}` here
|
||||
if let Some(Spanned { node: Constness::Const, span }) = constness {
|
||||
self.struct_span_err(span, "`const` cannot modify an inherent impl")
|
||||
.help("only a trait impl can be `const`")
|
||||
.emit();
|
||||
}
|
||||
|
||||
// impl Type
|
||||
ItemKind::Impl {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
generics,
|
||||
of_trait: None,
|
||||
self_ty: ty_first,
|
||||
|
@ -26,10 +26,12 @@ struct BoundModifiers {
|
||||
}
|
||||
|
||||
impl BoundModifiers {
|
||||
fn trait_bound_modifier(&self) -> TraitBoundModifier {
|
||||
match self.maybe {
|
||||
Some(_) => TraitBoundModifier::Maybe,
|
||||
None => TraitBoundModifier::None,
|
||||
fn to_trait_bound_modifier(&self) -> TraitBoundModifier {
|
||||
match (self.maybe, self.maybe_const) {
|
||||
(None, None) => TraitBoundModifier::None,
|
||||
(Some(_), None) => TraitBoundModifier::Maybe,
|
||||
(None, Some(_)) => TraitBoundModifier::MaybeConst,
|
||||
(Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -214,7 +216,7 @@ impl<'a> Parser<'a> {
|
||||
) -> PResult<'a, TyKind> {
|
||||
assert_ne!(self.token, token::Question);
|
||||
|
||||
let poly_trait_ref = PolyTraitRef::new(generic_params, path, None, lo.to(self.prev_span));
|
||||
let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span));
|
||||
let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
|
||||
if parse_plus {
|
||||
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
|
||||
@ -556,9 +558,9 @@ impl<'a> Parser<'a> {
|
||||
self.expect(&token::CloseDelim(token::Paren))?;
|
||||
}
|
||||
|
||||
let constness = modifiers.maybe_const.map(|_| ast::Constness::NotConst);
|
||||
let poly_trait = PolyTraitRef::new(lifetime_defs, path, constness, lo.to(self.prev_span));
|
||||
Ok(GenericBound::Trait(poly_trait, modifiers.trait_bound_modifier()))
|
||||
let modifier = modifiers.to_trait_bound_modifier();
|
||||
let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
|
||||
Ok(GenericBound::Trait(poly_trait, modifier))
|
||||
}
|
||||
|
||||
/// Optionally parses `for<$generic_params>`.
|
||||
|
@ -91,7 +91,7 @@ where
|
||||
let ty::GenericPredicates { parent: _, predicates } = predicates;
|
||||
for (predicate, _span) in predicates {
|
||||
match predicate {
|
||||
ty::Predicate::Trait(poly_predicate) => {
|
||||
ty::Predicate::Trait(poly_predicate, _) => {
|
||||
let ty::TraitPredicate { trait_ref } = *poly_predicate.skip_binder();
|
||||
if self.visit_trait(trait_ref) {
|
||||
return true;
|
||||
@ -1235,7 +1235,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
||||
// The traits' privacy in bodies is already checked as a part of trait object types.
|
||||
let bounds = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
|
||||
|
||||
for (trait_predicate, _) in bounds.trait_bounds {
|
||||
for (trait_predicate, _, _) in bounds.trait_bounds {
|
||||
if self.visit_trait(*trait_predicate.skip_binder()) {
|
||||
return;
|
||||
}
|
||||
|
@ -486,6 +486,7 @@ impl Sig for ast::Item {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
ref generics,
|
||||
ref of_trait,
|
||||
ref self_ty,
|
||||
@ -499,6 +500,9 @@ impl Sig for ast::Item {
|
||||
text.push_str("unsafe ");
|
||||
}
|
||||
text.push_str("impl");
|
||||
if constness == ast::Constness::Const {
|
||||
text.push_str(" const");
|
||||
}
|
||||
|
||||
let generics_sig = generics.make(offset + text.len(), id, scx)?;
|
||||
text.push_str(&generics_sig.text);
|
||||
|
@ -94,7 +94,7 @@ impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> {
|
||||
use rustc::ty::Predicate;
|
||||
|
||||
match self {
|
||||
Predicate::Trait(predicate) => predicate.lower(),
|
||||
Predicate::Trait(predicate, _) => predicate.lower(),
|
||||
Predicate::RegionOutlives(predicate) => predicate.lower(),
|
||||
Predicate::TypeOutlives(predicate) => predicate.lower(),
|
||||
Predicate::Projection(predicate) => predicate.lower(),
|
||||
|
@ -2,7 +2,7 @@ use rustc::hir::map as hir_map;
|
||||
use rustc::session::CrateDisambiguator;
|
||||
use rustc::traits::{self};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::{self, ToPredicate, Ty, TyCtxt};
|
||||
use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
@ -58,6 +58,7 @@ fn sized_constraint_for_ty(tcx: TyCtxt<'tcx>, adtdef: &ty::AdtDef, ty: Ty<'tcx>)
|
||||
def_id: sized_trait,
|
||||
substs: tcx.mk_substs_trait(ty, &[]),
|
||||
})
|
||||
.without_const()
|
||||
.to_predicate();
|
||||
let predicates = tcx.predicates_of(adtdef.did).predicates;
|
||||
if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] }
|
||||
|
@ -3,6 +3,8 @@
|
||||
//! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an
|
||||
//! instance of `AstConv`.
|
||||
|
||||
// ignore-tidy-filelength
|
||||
|
||||
use crate::collect::PlaceholderHirTyCollector;
|
||||
use crate::lint;
|
||||
use crate::middle::lang_items::SizedTraitLangItem;
|
||||
@ -17,7 +19,7 @@ use rustc::traits::astconv_object_safety_violations;
|
||||
use rustc::traits::error_reporting::report_object_safety_error;
|
||||
use rustc::traits::wf::object_region_bounds;
|
||||
use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
|
||||
use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||
use rustc::ty::{GenericParamDef, GenericParamDefKind};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId};
|
||||
@ -31,7 +33,7 @@ use rustc_span::symbol::sym;
|
||||
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
use smallvec::SmallVec;
|
||||
use syntax::ast;
|
||||
use syntax::ast::{self, Constness};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
@ -48,6 +50,8 @@ pub trait AstConv<'tcx> {
|
||||
|
||||
fn item_def_id(&self) -> Option<DefId>;
|
||||
|
||||
fn default_constness_for_trait_bounds(&self) -> Constness;
|
||||
|
||||
/// Returns predicates in scope of the form `X: Foo`, where `X` is
|
||||
/// a type parameter `X` with the given id `def_id`. This is a
|
||||
/// subset of the full set of predicates.
|
||||
@ -918,6 +922,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
&self,
|
||||
trait_ref: &hir::TraitRef<'_>,
|
||||
span: Span,
|
||||
constness: Constness,
|
||||
self_ty: Ty<'tcx>,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
speculative: bool,
|
||||
@ -946,7 +951,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
);
|
||||
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
|
||||
|
||||
bounds.trait_bounds.push((poly_trait_ref, span));
|
||||
bounds.trait_bounds.push((poly_trait_ref, span, constness));
|
||||
|
||||
let mut dup_bindings = FxHashMap::default();
|
||||
for binding in &assoc_bindings {
|
||||
@ -992,12 +997,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
pub fn instantiate_poly_trait_ref(
|
||||
&self,
|
||||
poly_trait_ref: &hir::PolyTraitRef<'_>,
|
||||
constness: Constness,
|
||||
self_ty: Ty<'tcx>,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
) -> Option<Vec<Span>> {
|
||||
self.instantiate_poly_trait_ref_inner(
|
||||
&poly_trait_ref.trait_ref,
|
||||
poly_trait_ref.span,
|
||||
constness,
|
||||
self_ty,
|
||||
bounds,
|
||||
false,
|
||||
@ -1180,18 +1187,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
let mut trait_bounds = Vec::new();
|
||||
let mut region_bounds = Vec::new();
|
||||
|
||||
let constness = self.default_constness_for_trait_bounds();
|
||||
for ast_bound in ast_bounds {
|
||||
match *ast_bound {
|
||||
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => {
|
||||
trait_bounds.push(b)
|
||||
trait_bounds.push((b, constness))
|
||||
}
|
||||
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => {
|
||||
trait_bounds.push((b, Constness::NotConst))
|
||||
}
|
||||
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
|
||||
hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
|
||||
}
|
||||
}
|
||||
|
||||
for bound in trait_bounds {
|
||||
let _ = self.instantiate_poly_trait_ref(bound, param_ty, bounds);
|
||||
for (bound, constness) in trait_bounds {
|
||||
let _ = self.instantiate_poly_trait_ref(bound, constness, param_ty, bounds);
|
||||
}
|
||||
|
||||
bounds.region_bounds.extend(
|
||||
@ -1225,7 +1236,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
let mut bounds = Bounds::default();
|
||||
|
||||
self.add_bounds(param_ty, ast_bounds, &mut bounds);
|
||||
bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id());
|
||||
bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id());
|
||||
|
||||
bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
|
||||
if !self.is_unsized(ast_bounds, span) { Some(span) } else { None }
|
||||
@ -1416,15 +1427,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
let mut potential_assoc_types = Vec::new();
|
||||
let dummy_self = self.tcx().types.trait_object_dummy_self;
|
||||
for trait_bound in trait_bounds.iter().rev() {
|
||||
let cur_potential_assoc_types =
|
||||
self.instantiate_poly_trait_ref(trait_bound, dummy_self, &mut bounds);
|
||||
let cur_potential_assoc_types = self.instantiate_poly_trait_ref(
|
||||
trait_bound,
|
||||
Constness::NotConst,
|
||||
dummy_self,
|
||||
&mut bounds,
|
||||
);
|
||||
potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
|
||||
}
|
||||
|
||||
// Expand trait aliases recursively and check that only one regular (non-auto) trait
|
||||
// is used and no 'maybe' bounds are used.
|
||||
let expanded_traits =
|
||||
traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().cloned());
|
||||
let expanded_traits = traits::expand_trait_aliases(
|
||||
tcx,
|
||||
bounds.trait_bounds.iter().map(|&(a, b, _)| (a.clone(), b)),
|
||||
);
|
||||
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
|
||||
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
|
||||
if regular_traits.len() > 1 {
|
||||
@ -1480,16 +1497,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
let regular_traits_refs_spans = bounds
|
||||
.trait_bounds
|
||||
.into_iter()
|
||||
.filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
|
||||
.filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
|
||||
|
||||
for (base_trait_ref, span, constness) in regular_traits_refs_spans {
|
||||
assert_eq!(constness, ast::Constness::NotConst);
|
||||
|
||||
for (base_trait_ref, span) in regular_traits_refs_spans {
|
||||
for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) {
|
||||
debug!(
|
||||
"conv_object_ty_poly_trait_ref: observing object predicate `{:?}`",
|
||||
trait_ref
|
||||
);
|
||||
match trait_ref {
|
||||
ty::Predicate::Trait(pred) => {
|
||||
ty::Predicate::Trait(pred, _) => {
|
||||
associated_types.entry(span).or_default().extend(
|
||||
tcx.associated_items(pred.def_id())
|
||||
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||
@ -2948,7 +2967,7 @@ pub struct Bounds<'tcx> {
|
||||
|
||||
/// A list of trait bounds. So if you had `T: Debug` this would be
|
||||
/// `T: Debug`. Note that the self-type is explicit here.
|
||||
pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>,
|
||||
pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>,
|
||||
|
||||
/// A list of projection equality bounds. So if you had `T:
|
||||
/// Iterator<Item = u32>` this would include `<T as
|
||||
@ -2979,7 +2998,7 @@ impl<'tcx> Bounds<'tcx> {
|
||||
def_id: sized,
|
||||
substs: tcx.mk_substs_trait(param_ty, &[]),
|
||||
});
|
||||
(trait_ref.to_predicate(), span)
|
||||
(trait_ref.without_const().to_predicate(), span)
|
||||
})
|
||||
});
|
||||
|
||||
@ -2996,11 +3015,10 @@ impl<'tcx> Bounds<'tcx> {
|
||||
let outlives = ty::OutlivesPredicate(param_ty, region_bound);
|
||||
(ty::Binder::bind(outlives).to_predicate(), span)
|
||||
})
|
||||
.chain(
|
||||
self.trait_bounds
|
||||
.iter()
|
||||
.map(|&(bound_trait_ref, span)| (bound_trait_ref.to_predicate(), span)),
|
||||
)
|
||||
.chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
|
||||
let predicate = bound_trait_ref.with_constness(constness).to_predicate();
|
||||
(predicate, span)
|
||||
}))
|
||||
.chain(
|
||||
self.projection_bounds
|
||||
.iter()
|
||||
|
@ -5,7 +5,7 @@ use rustc::infer::{InferCtxt, InferOk};
|
||||
use rustc::session::DiagnosticMessageId;
|
||||
use rustc::traits::{self, TraitEngine};
|
||||
use rustc::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
|
||||
use rustc::ty::{self, TraitRef, Ty, TyCtxt};
|
||||
use rustc::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
|
||||
use rustc::ty::{ToPredicate, TypeFoldable};
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
@ -122,8 +122,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
||||
|
||||
let cause = traits::ObligationCause::misc(self.span, self.body_id);
|
||||
|
||||
let obligation =
|
||||
traits::Obligation::new(cause.clone(), self.param_env, trait_ref.to_predicate());
|
||||
let obligation = traits::Obligation::new(
|
||||
cause.clone(),
|
||||
self.param_env,
|
||||
trait_ref.without_const().to_predicate(),
|
||||
);
|
||||
if !self.infcx.predicate_may_hold(&obligation) {
|
||||
debug!("overloaded_deref_ty: cannot match obligation");
|
||||
return None;
|
||||
|
@ -564,7 +564,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
let obligation = queue.remove(0);
|
||||
debug!("coerce_unsized resolve step: {:?}", obligation);
|
||||
let trait_ref = match obligation.predicate {
|
||||
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
|
||||
ty::Predicate::Trait(ref tr, _) if traits.contains(&tr.def_id()) => {
|
||||
if unsize_did == tr.def_id() {
|
||||
let sty = &tr.skip_binder().input_types().nth(1).unwrap().kind;
|
||||
if let ty::Tuple(..) = sty {
|
||||
|
@ -232,7 +232,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||
let predicate_matches_closure = |p: &'_ Predicate<'tcx>| {
|
||||
let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env);
|
||||
match (predicate, p) {
|
||||
(Predicate::Trait(a), Predicate::Trait(b)) => relator.relate(a, b).is_ok(),
|
||||
(Predicate::Trait(a, _), Predicate::Trait(b, _)) => relator.relate(a, b).is_ok(),
|
||||
(Predicate::Projection(a), Predicate::Projection(b)) => {
|
||||
relator.relate(a, b).is_ok()
|
||||
}
|
||||
|
@ -569,7 +569,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
||||
|
||||
traits::elaborate_predicates(self.tcx, predicates.predicates.clone())
|
||||
.filter_map(|predicate| match predicate {
|
||||
ty::Predicate::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => {
|
||||
ty::Predicate::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => {
|
||||
Some(trait_pred)
|
||||
}
|
||||
_ => None,
|
||||
|
@ -17,7 +17,7 @@ use rustc::traits;
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::subst::{InternalSubsts, SubstsRef};
|
||||
use rustc::ty::GenericParamDefKind;
|
||||
use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable};
|
||||
use rustc::ty::{self, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TypeFoldable, WithConstness};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
@ -322,7 +322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span,
|
||||
self.body_id,
|
||||
self.param_env,
|
||||
poly_trait_ref.to_predicate(),
|
||||
poly_trait_ref.without_const().to_predicate(),
|
||||
);
|
||||
|
||||
// Now we want to know if this can be matched
|
||||
|
@ -25,6 +25,7 @@ use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
||||
use rustc::ty::GenericParamDefKind;
|
||||
use rustc::ty::{
|
||||
self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
|
||||
WithConstness,
|
||||
};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
@ -824,7 +825,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
// FIXME: do we want to commit to this behavior for param bounds?
|
||||
|
||||
let bounds = self.param_env.caller_bounds.iter().filter_map(|predicate| match *predicate {
|
||||
ty::Predicate::Trait(ref trait_predicate) => {
|
||||
ty::Predicate::Trait(ref trait_predicate, _) => {
|
||||
match trait_predicate.skip_binder().trait_ref.self_ty().kind {
|
||||
ty::Param(ref p) if *p == param_ty => Some(trait_predicate.to_poly_trait_ref()),
|
||||
_ => None,
|
||||
@ -1394,7 +1395,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
TraitCandidate(trait_ref) => {
|
||||
let predicate = trait_ref.to_predicate();
|
||||
let predicate = trait_ref.without_const().to_predicate();
|
||||
let obligation = traits::Obligation::new(cause, self.param_env, predicate);
|
||||
if !self.predicate_may_hold(&obligation) {
|
||||
if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) {
|
||||
@ -1428,7 +1429,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||
let o = self.resolve_vars_if_possible(&o);
|
||||
if !self.predicate_may_hold(&o) {
|
||||
result = ProbeResult::NoMatch;
|
||||
if let &ty::Predicate::Trait(ref pred) = &o.predicate {
|
||||
if let &ty::Predicate::Trait(ref pred, _) = &o.predicate {
|
||||
possibly_unsatisfied_predicates.push(pred.skip_binder().trait_ref);
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use rustc::hir::map::Map;
|
||||
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc::traits::Obligation;
|
||||
use rustc::ty::print::with_crate_prefix;
|
||||
use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
@ -57,7 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span,
|
||||
self.body_id,
|
||||
self.param_env,
|
||||
poly_trait_ref.to_predicate(),
|
||||
poly_trait_ref.without_const().to_predicate(),
|
||||
);
|
||||
self.predicate_may_hold(&obligation)
|
||||
})
|
||||
|
@ -90,6 +90,7 @@ pub mod writeback;
|
||||
use crate::astconv::{AstConv, PathSeg};
|
||||
use crate::middle::lang_items;
|
||||
use crate::namespace::Namespace;
|
||||
use rustc::hir::map::blocks::FnLikeNode;
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||
use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
||||
@ -112,7 +113,7 @@ use rustc::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSel
|
||||
use rustc::ty::util::{Discr, IntTypeExt, Representability};
|
||||
use rustc::ty::{
|
||||
self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef,
|
||||
ToPredicate, Ty, TyCtxt, UserType,
|
||||
ToPredicate, Ty, TyCtxt, UserType, WithConstness,
|
||||
};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
@ -1421,7 +1422,7 @@ fn check_fn<'a, 'tcx>(
|
||||
inherited.register_predicate(traits::Obligation::new(
|
||||
cause,
|
||||
param_env,
|
||||
trait_ref.to_predicate(),
|
||||
trait_ref.without_const().to_predicate(),
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -2610,6 +2611,16 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
||||
None
|
||||
}
|
||||
|
||||
fn default_constness_for_trait_bounds(&self) -> ast::Constness {
|
||||
// FIXME: refactor this into a method
|
||||
let node = self.tcx.hir().get(self.body_id);
|
||||
if let Some(fn_like) = FnLikeNode::from_node(node) {
|
||||
fn_like.constness()
|
||||
} else {
|
||||
ast::Constness::NotConst
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||
@ -2621,7 +2632,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
||||
parent: None,
|
||||
predicates: tcx.arena.alloc_from_iter(self.param_env.caller_bounds.iter().filter_map(
|
||||
|&predicate| match predicate {
|
||||
ty::Predicate::Trait(ref data)
|
||||
ty::Predicate::Trait(ref data, _)
|
||||
if data.skip_binder().self_ty().is_param(index) =>
|
||||
{
|
||||
// HACK(eddyb) should get the original `Span`.
|
||||
@ -3693,7 +3704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ty::Predicate::Projection(ref data) => {
|
||||
Some((data.to_poly_trait_ref(self.tcx), obligation))
|
||||
}
|
||||
ty::Predicate::Trait(ref data) => Some((data.to_poly_trait_ref(), obligation)),
|
||||
ty::Predicate::Trait(ref data, _) => Some((data.to_poly_trait_ref(), obligation)),
|
||||
ty::Predicate::Subtype(..) => None,
|
||||
ty::Predicate::RegionOutlives(..) => None,
|
||||
ty::Predicate::TypeOutlives(..) => None,
|
||||
@ -3996,7 +4007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
|
||||
if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate {
|
||||
// Collect the argument position for all arguments that could have caused this
|
||||
// `FulfillmentError`.
|
||||
let mut referenced_in = final_arg_types
|
||||
@ -4040,7 +4051,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if let hir::ExprKind::Path(qpath) = &path.kind {
|
||||
if let hir::QPath::Resolved(_, path) = &qpath {
|
||||
for error in errors {
|
||||
if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
|
||||
if let ty::Predicate::Trait(predicate, _) = error.obligation.predicate {
|
||||
// If any of the type arguments in this path segment caused the
|
||||
// `FullfillmentError`, point at its span (#61860).
|
||||
for arg in path
|
||||
|
@ -6,7 +6,9 @@ use rustc::middle::lang_items;
|
||||
use rustc::session::parse::feature_err;
|
||||
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
use rustc::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc::ty::{self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::{
|
||||
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{struct_span_err, DiagnosticBuilder};
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -953,7 +955,8 @@ fn receiver_is_implemented(
|
||||
substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
|
||||
};
|
||||
|
||||
let obligation = traits::Obligation::new(cause, fcx.param_env, trait_ref.to_predicate());
|
||||
let obligation =
|
||||
traits::Obligation::new(cause, fcx.param_env, trait_ref.without_const().to_predicate());
|
||||
|
||||
if fcx.predicate_must_hold_modulo_regions(&obligation) {
|
||||
true
|
||||
|
@ -20,6 +20,7 @@ use crate::constrained_generic_params as cgp;
|
||||
use crate::lint;
|
||||
use crate::middle::resolve_lifetime as rl;
|
||||
use crate::middle::weak_lang_items;
|
||||
use rustc::hir::map::blocks::FnLikeNode;
|
||||
use rustc::hir::map::Map;
|
||||
use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc::mir::mono::Linkage;
|
||||
@ -30,7 +31,7 @@ use rustc::ty::subst::GenericArgKind;
|
||||
use rustc::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc::ty::util::Discr;
|
||||
use rustc::ty::util::IntTypeExt;
|
||||
use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt};
|
||||
use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, WithConstness};
|
||||
use rustc::ty::{ReprOptions, ToPredicate};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@ -286,6 +287,22 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
|
||||
Some(self.item_def_id)
|
||||
}
|
||||
|
||||
fn default_constness_for_trait_bounds(&self) -> ast::Constness {
|
||||
// FIXME: refactor this into a method
|
||||
let hir_id = self
|
||||
.tcx
|
||||
.hir()
|
||||
.as_local_hir_id(self.item_def_id)
|
||||
.expect("Non-local call to local provider is_const_fn");
|
||||
|
||||
let node = self.tcx.hir().get(hir_id);
|
||||
if let Some(fn_like) = FnLikeNode::from_node(node) {
|
||||
fn_like.constness()
|
||||
} else {
|
||||
ast::Constness::NotConst
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
|
||||
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id))
|
||||
}
|
||||
@ -409,7 +426,8 @@ fn type_param_predicates(
|
||||
// Implied `Self: Trait` and supertrait bounds.
|
||||
if param_id == item_hir_id {
|
||||
let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id);
|
||||
extend = Some((identity_trait_ref.to_predicate(), item.span));
|
||||
extend =
|
||||
Some((identity_trait_ref.without_const().to_predicate(), item.span));
|
||||
}
|
||||
generics
|
||||
}
|
||||
@ -430,7 +448,7 @@ fn type_param_predicates(
|
||||
icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true))
|
||||
.into_iter()
|
||||
.filter(|(predicate, _)| match predicate {
|
||||
ty::Predicate::Trait(ref data) => data.skip_binder().self_ty().is_param(index),
|
||||
ty::Predicate::Trait(ref data, _) => data.skip_binder().self_ty().is_param(index),
|
||||
_ => false,
|
||||
}),
|
||||
);
|
||||
@ -451,6 +469,7 @@ impl ItemCtxt<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
only_self_bounds: OnlySelfBounds,
|
||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||
let constness = self.default_constness_for_trait_bounds();
|
||||
let from_ty_params = ast_generics
|
||||
.params
|
||||
.iter()
|
||||
@ -459,7 +478,7 @@ impl ItemCtxt<'tcx> {
|
||||
_ => None,
|
||||
})
|
||||
.flat_map(|bounds| bounds.iter())
|
||||
.flat_map(|b| predicates_from_bound(self, ty, b));
|
||||
.flat_map(|b| predicates_from_bound(self, ty, b, constness));
|
||||
|
||||
let from_where_clauses = ast_generics
|
||||
.where_clause
|
||||
@ -479,7 +498,7 @@ impl ItemCtxt<'tcx> {
|
||||
};
|
||||
bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b)))
|
||||
})
|
||||
.flat_map(|(bt, b)| predicates_from_bound(self, bt, b));
|
||||
.flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness));
|
||||
|
||||
from_ty_params.chain(from_where_clauses).collect()
|
||||
}
|
||||
@ -855,7 +874,7 @@ fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredi
|
||||
// which will, in turn, reach indirect supertraits.
|
||||
for &(pred, span) in superbounds {
|
||||
debug!("superbound: {:?}", pred);
|
||||
if let ty::Predicate::Trait(bound) = pred {
|
||||
if let ty::Predicate::Trait(bound, _) = pred {
|
||||
tcx.at(span).super_predicates_of(bound.def_id());
|
||||
}
|
||||
}
|
||||
@ -2054,7 +2073,7 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
|
||||
let span = tcx.def_span(def_id);
|
||||
result.predicates =
|
||||
tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
|
||||
ty::TraitRef::identity(tcx, def_id).to_predicate(),
|
||||
ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(),
|
||||
span,
|
||||
))));
|
||||
}
|
||||
@ -2104,6 +2123,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
|
||||
let mut is_default_impl_trait = None;
|
||||
|
||||
let icx = ItemCtxt::new(tcx, def_id);
|
||||
let constness = icx.default_constness_for_trait_bounds();
|
||||
|
||||
const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty();
|
||||
|
||||
@ -2228,7 +2248,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
|
||||
// (see below). Recall that a default impl is not itself an impl, but rather a
|
||||
// set of defaults that can be incorporated into another impl.
|
||||
if let Some(trait_ref) = is_default_impl_trait {
|
||||
predicates.push((trait_ref.to_poly_trait_ref().to_predicate(), tcx.def_span(def_id)));
|
||||
predicates.push((
|
||||
trait_ref.to_poly_trait_ref().without_const().to_predicate(),
|
||||
tcx.def_span(def_id),
|
||||
));
|
||||
}
|
||||
|
||||
// Collect the region predicates that were declared inline as
|
||||
@ -2302,11 +2325,18 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
|
||||
|
||||
for bound in bound_pred.bounds.iter() {
|
||||
match bound {
|
||||
&hir::GenericBound::Trait(ref poly_trait_ref, _) => {
|
||||
&hir::GenericBound::Trait(ref poly_trait_ref, modifier) => {
|
||||
let constness = match modifier {
|
||||
hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst,
|
||||
hir::TraitBoundModifier::None => constness,
|
||||
hir::TraitBoundModifier::Maybe => bug!("this wasn't handled"),
|
||||
};
|
||||
|
||||
let mut bounds = Bounds::default();
|
||||
let _ = AstConv::instantiate_poly_trait_ref(
|
||||
&icx,
|
||||
poly_trait_ref,
|
||||
constness,
|
||||
ty,
|
||||
&mut bounds,
|
||||
);
|
||||
@ -2482,11 +2512,18 @@ fn predicates_from_bound<'tcx>(
|
||||
astconv: &dyn AstConv<'tcx>,
|
||||
param_ty: Ty<'tcx>,
|
||||
bound: &'tcx hir::GenericBound<'tcx>,
|
||||
constness: ast::Constness,
|
||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||
match *bound {
|
||||
hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => {
|
||||
hir::GenericBound::Trait(ref tr, modifier) => {
|
||||
let constness = match modifier {
|
||||
hir::TraitBoundModifier::Maybe => return vec![],
|
||||
hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst,
|
||||
hir::TraitBoundModifier::None => constness,
|
||||
};
|
||||
|
||||
let mut bounds = Bounds::default();
|
||||
let _ = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut bounds);
|
||||
let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds);
|
||||
bounds.predicates(astconv.tcx(), param_ty)
|
||||
}
|
||||
hir::GenericBound::Outlives(ref lifetime) => {
|
||||
@ -2494,7 +2531,6 @@ fn predicates_from_bound<'tcx>(
|
||||
let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region));
|
||||
vec![(ty::Predicate::TypeOutlives(pred), lifetime.span)]
|
||||
}
|
||||
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => vec![],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,6 +380,7 @@ pub fn hir_trait_to_predicates<'tcx>(
|
||||
&item_cx,
|
||||
hir_trait,
|
||||
DUMMY_SP,
|
||||
syntax::ast::Constness::NotConst,
|
||||
tcx.types.err,
|
||||
&mut bounds,
|
||||
true,
|
||||
|
@ -462,7 +462,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
|
||||
.filter(|p| {
|
||||
!orig_bounds.contains(p)
|
||||
|| match p {
|
||||
&&ty::Predicate::Trait(pred) => pred.def_id() == sized_trait,
|
||||
ty::Predicate::Trait(pred, _) => pred.def_id() == sized_trait,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc::infer::InferOk;
|
||||
use rustc::traits;
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::ToPredicate;
|
||||
use rustc::ty::{ToPredicate, WithConstness};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_span::DUMMY_SP;
|
||||
@ -64,7 +64,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
||||
match infcx.evaluate_obligation(&traits::Obligation::new(
|
||||
cause,
|
||||
param_env,
|
||||
trait_ref.to_predicate(),
|
||||
trait_ref.without_const().to_predicate(),
|
||||
)) {
|
||||
Ok(eval_result) => eval_result.may_apply(),
|
||||
Err(traits::OverflowError) => true, // overflow doesn't mean yes *or* no
|
||||
|
@ -482,7 +482,7 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
|
||||
use rustc::ty::Predicate;
|
||||
|
||||
match *self {
|
||||
Predicate::Trait(ref pred) => Some(pred.clean(cx)),
|
||||
Predicate::Trait(ref pred, _) => Some(pred.clean(cx)),
|
||||
Predicate::Subtype(ref pred) => Some(pred.clean(cx)),
|
||||
Predicate::RegionOutlives(ref pred) => pred.clean(cx),
|
||||
Predicate::TypeOutlives(ref pred) => pred.clean(cx),
|
||||
|
@ -141,7 +141,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId)
|
||||
.predicates
|
||||
.iter()
|
||||
.filter_map(|(pred, _)| {
|
||||
if let ty::Predicate::Trait(ref pred) = *pred {
|
||||
if let ty::Predicate::Trait(ref pred, _) = *pred {
|
||||
if pred.skip_binder().trait_ref.self_ty() == self_ty {
|
||||
Some(pred.def_id())
|
||||
} else {
|
||||
|
@ -203,6 +203,7 @@ pub struct Impl<'hir> {
|
||||
pub unsafety: hir::Unsafety,
|
||||
pub polarity: hir::ImplPolarity,
|
||||
pub defaultness: hir::Defaultness,
|
||||
pub constness: ast::Constness,
|
||||
pub generics: &'hir hir::Generics<'hir>,
|
||||
pub trait_: &'hir Option<hir::TraitRef<'hir>>,
|
||||
pub for_: &'hir hir::Ty<'hir>,
|
||||
|
@ -361,6 +361,7 @@ impl clean::GenericBound {
|
||||
let modifier_str = match modifier {
|
||||
hir::TraitBoundModifier::None => "",
|
||||
hir::TraitBoundModifier::Maybe => "?",
|
||||
hir::TraitBoundModifier::MaybeConst => "?const",
|
||||
};
|
||||
if f.alternate() {
|
||||
write!(f, "{}{:#}", modifier_str, ty.print())
|
||||
|
@ -562,6 +562,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
ref generics,
|
||||
ref of_trait,
|
||||
self_ty,
|
||||
@ -576,6 +577,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
generics,
|
||||
trait_: of_trait,
|
||||
for_: self_ty,
|
||||
|
@ -13,75 +13,43 @@ use crate::time::Duration;
|
||||
|
||||
use libc::{c_int, c_void};
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "solaris",
|
||||
target_os = "haiku",
|
||||
target_os = "l4re"
|
||||
)))]
|
||||
use crate::sys::net::netc::IPV6_ADD_MEMBERSHIP;
|
||||
#[cfg(not(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "solaris",
|
||||
target_os = "haiku",
|
||||
target_os = "l4re"
|
||||
)))]
|
||||
use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP;
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "solaris",
|
||||
target_os = "haiku",
|
||||
target_os = "l4re"
|
||||
))]
|
||||
use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "ios",
|
||||
target_os = "macos",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "solaris",
|
||||
target_os = "haiku",
|
||||
target_os = "l4re"
|
||||
))]
|
||||
use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(
|
||||
target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "ios", target_os = "macos",
|
||||
target_os = "openbsd", target_os = "netbsd",
|
||||
target_os = "solaris", target_os = "haiku", target_os = "l4re"))] {
|
||||
use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
|
||||
use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
|
||||
} else {
|
||||
use crate::sys::net::netc::IPV6_ADD_MEMBERSHIP;
|
||||
use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "haiku"
|
||||
))]
|
||||
use libc::MSG_NOSIGNAL;
|
||||
#[cfg(not(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "haiku"
|
||||
)))]
|
||||
const MSG_NOSIGNAL: c_int = 0x0;
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(
|
||||
target_os = "linux", target_os = "android",
|
||||
target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "openbsd", target_os = "netbsd",
|
||||
target_os = "haiku"))] {
|
||||
use libc::MSG_NOSIGNAL;
|
||||
} else {
|
||||
const MSG_NOSIGNAL: c_int = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(
|
||||
target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "openbsd", target_os = "netbsd",
|
||||
target_os = "solaris"))] {
|
||||
use libc::c_uchar;
|
||||
type IpV4MultiCastType = c_uchar;
|
||||
} else {
|
||||
type IpV4MultiCastType = c_int;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// sockaddr and misc bindings
|
||||
@ -566,20 +534,30 @@ impl UdpSocket {
|
||||
}
|
||||
|
||||
pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
|
||||
setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_int)
|
||||
setsockopt(
|
||||
&self.inner,
|
||||
c::IPPROTO_IP,
|
||||
c::IP_MULTICAST_LOOP,
|
||||
multicast_loop_v4 as IpV4MultiCastType,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
|
||||
let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?;
|
||||
let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?;
|
||||
Ok(raw != 0)
|
||||
}
|
||||
|
||||
pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
|
||||
setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_int)
|
||||
setsockopt(
|
||||
&self.inner,
|
||||
c::IPPROTO_IP,
|
||||
c::IP_MULTICAST_TTL,
|
||||
multicast_ttl_v4 as IpV4MultiCastType,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
|
||||
let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?;
|
||||
let raw: IpV4MultiCastType = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?;
|
||||
Ok(raw as u32)
|
||||
}
|
||||
|
||||
|
@ -266,12 +266,24 @@ pub const CRATE_NODE_ID: NodeId = NodeId::from_u32_const(0);
|
||||
/// small, positive ids.
|
||||
pub const DUMMY_NODE_ID: NodeId = NodeId::MAX;
|
||||
|
||||
/// A modifier on a bound, currently this is only used for `?Sized`, where the
|
||||
/// modifier is `Maybe`. Negative bounds should also be handled here.
|
||||
/// A modifier on a bound, e.g., `?Sized` or `?const Trait`.
|
||||
///
|
||||
/// Negative bounds should also be handled here.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
|
||||
pub enum TraitBoundModifier {
|
||||
/// No modifiers
|
||||
None,
|
||||
|
||||
/// `?Trait`
|
||||
Maybe,
|
||||
|
||||
/// `?const Trait`
|
||||
MaybeConst,
|
||||
|
||||
/// `?const ?Trait`
|
||||
//
|
||||
// This parses but will be rejected during AST validation.
|
||||
MaybeConstMaybe,
|
||||
}
|
||||
|
||||
/// The AST represents all type param bounds as types.
|
||||
@ -1033,7 +1045,7 @@ impl Expr {
|
||||
pub fn to_bound(&self) -> Option<GenericBound> {
|
||||
match &self.kind {
|
||||
ExprKind::Path(None, path) => Some(GenericBound::Trait(
|
||||
PolyTraitRef::new(Vec::new(), path.clone(), None, self.span),
|
||||
PolyTraitRef::new(Vec::new(), path.clone(), self.span),
|
||||
TraitBoundModifier::None,
|
||||
)),
|
||||
_ => None,
|
||||
@ -2158,7 +2170,8 @@ impl IsAsync {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum Constness {
|
||||
Const,
|
||||
NotConst,
|
||||
@ -2376,15 +2389,6 @@ pub enum AttrKind {
|
||||
pub struct TraitRef {
|
||||
pub path: Path,
|
||||
pub ref_id: NodeId,
|
||||
|
||||
/// The `const` modifier, if any, that appears before this trait.
|
||||
///
|
||||
/// | | `constness` |
|
||||
/// |----------------|-----------------------------|
|
||||
/// | `Trait` | `None` |
|
||||
/// | `const Trait` | `Some(Constness::Const)` |
|
||||
/// | `?const Trait` | `Some(Constness::NotConst)` |
|
||||
pub constness: Option<Constness>,
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||
@ -2399,15 +2403,10 @@ pub struct PolyTraitRef {
|
||||
}
|
||||
|
||||
impl PolyTraitRef {
|
||||
pub fn new(
|
||||
generic_params: Vec<GenericParam>,
|
||||
path: Path,
|
||||
constness: Option<Constness>,
|
||||
span: Span,
|
||||
) -> Self {
|
||||
pub fn new(generic_params: Vec<GenericParam>, path: Path, span: Span) -> Self {
|
||||
PolyTraitRef {
|
||||
bound_generic_params: generic_params,
|
||||
trait_ref: TraitRef { path, constness, ref_id: DUMMY_NODE_ID },
|
||||
trait_ref: TraitRef { path, ref_id: DUMMY_NODE_ID },
|
||||
span,
|
||||
}
|
||||
}
|
||||
@ -2618,6 +2617,7 @@ pub enum ItemKind {
|
||||
unsafety: Unsafety,
|
||||
polarity: ImplPolarity,
|
||||
defaultness: Defaultness,
|
||||
constness: Constness,
|
||||
generics: Generics,
|
||||
|
||||
/// The trait being implemented, if any.
|
||||
|
@ -838,8 +838,7 @@ pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noop_visit_trait_ref<T: MutVisitor>(tr: &mut TraitRef, vis: &mut T) {
|
||||
let TraitRef { path, ref_id, constness: _ } = tr;
|
||||
pub fn noop_visit_trait_ref<T: MutVisitor>(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) {
|
||||
vis.visit_path(path);
|
||||
vis.visit_id(ref_id);
|
||||
}
|
||||
@ -922,6 +921,7 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
|
||||
unsafety: _,
|
||||
polarity: _,
|
||||
defaultness: _,
|
||||
constness: _,
|
||||
generics,
|
||||
of_trait,
|
||||
self_ty,
|
||||
|
@ -1230,6 +1230,7 @@ impl<'a> State<'a> {
|
||||
unsafety,
|
||||
polarity,
|
||||
defaultness,
|
||||
constness,
|
||||
ref generics,
|
||||
ref of_trait,
|
||||
ref self_ty,
|
||||
@ -1240,6 +1241,7 @@ impl<'a> State<'a> {
|
||||
self.print_defaultness(defaultness);
|
||||
self.print_unsafety(unsafety);
|
||||
self.word_nbsp("impl");
|
||||
self.print_constness(constness);
|
||||
|
||||
if !generics.params.is_empty() {
|
||||
self.print_generic_params(&generics.params);
|
||||
@ -2773,6 +2775,13 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
crate fn print_constness(&mut self, s: ast::Constness) {
|
||||
match s {
|
||||
ast::Constness::Const => self.word_nbsp("const"),
|
||||
ast::Constness::NotConst => {}
|
||||
}
|
||||
}
|
||||
|
||||
crate fn print_is_auto(&mut self, s: ast::IsAuto) {
|
||||
match s {
|
||||
ast::IsAuto::Yes => self.word_nbsp("auto"),
|
||||
|
@ -312,6 +312,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
||||
unsafety: _,
|
||||
polarity: _,
|
||||
defaultness: _,
|
||||
constness: _,
|
||||
ref generics,
|
||||
ref of_trait,
|
||||
ref self_ty,
|
||||
|
@ -25,6 +25,16 @@ fn main() {
|
||||
//~^^^ WARN unused variable: `Foo`
|
||||
}
|
||||
|
||||
let Foo = foo::Foo::Foo;
|
||||
//~^ ERROR variable `Foo` should have a snake case name
|
||||
//~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
|
||||
//~^^^ WARN unused variable: `Foo`
|
||||
|
||||
fn in_param(Foo: foo::Foo) {}
|
||||
//~^ ERROR variable `Foo` should have a snake case name
|
||||
//~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
|
||||
//~^^^ WARN unused variable: `Foo`
|
||||
|
||||
test(1);
|
||||
|
||||
let _ = Something { X: 0 };
|
||||
|
@ -6,6 +6,18 @@ LL | Foo => {}
|
||||
|
|
||||
= note: `#[warn(bindings_with_variant_name)]` on by default
|
||||
|
||||
warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
|
||||
--> $DIR/lint-uppercase-variables.rs:28:9
|
||||
|
|
||||
LL | let Foo = foo::Foo::Foo;
|
||||
| ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
|
||||
|
||||
warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
|
||||
--> $DIR/lint-uppercase-variables.rs:33:17
|
||||
|
|
||||
LL | fn in_param(Foo: foo::Foo) {}
|
||||
| ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
|
||||
|
||||
warning: unused variable: `Foo`
|
||||
--> $DIR/lint-uppercase-variables.rs:22:9
|
||||
|
|
||||
@ -19,6 +31,18 @@ LL | #![warn(unused)]
|
||||
| ^^^^^^
|
||||
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
|
||||
|
||||
warning: unused variable: `Foo`
|
||||
--> $DIR/lint-uppercase-variables.rs:28:9
|
||||
|
|
||||
LL | let Foo = foo::Foo::Foo;
|
||||
| ^^^ help: consider prefixing with an underscore: `_Foo`
|
||||
|
||||
warning: unused variable: `Foo`
|
||||
--> $DIR/lint-uppercase-variables.rs:33:17
|
||||
|
|
||||
LL | fn in_param(Foo: foo::Foo) {}
|
||||
| ^^^ help: consider prefixing with an underscore: `_Foo`
|
||||
|
||||
error: structure field `X` should have a snake case name
|
||||
--> $DIR/lint-uppercase-variables.rs:10:5
|
||||
|
|
||||
@ -49,6 +73,18 @@ error: variable `Foo` should have a snake case name
|
||||
LL | Foo => {}
|
||||
| ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: variable `Foo` should have a snake case name
|
||||
--> $DIR/lint-uppercase-variables.rs:28:9
|
||||
|
|
||||
LL | let Foo = foo::Foo::Foo;
|
||||
| ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
|
||||
|
||||
error: variable `Foo` should have a snake case name
|
||||
--> $DIR/lint-uppercase-variables.rs:33:17
|
||||
|
|
||||
LL | fn in_param(Foo: foo::Foo) {}
|
||||
| ^^^ help: convert the identifier to snake case (notice the capitalization): `foo`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0170`.
|
||||
|
26
src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs
Normal file
26
src/test/ui/pattern/issue-68393-let-pat-assoc-constant.rs
Normal file
@ -0,0 +1,26 @@
|
||||
pub enum EFoo {
|
||||
A,
|
||||
}
|
||||
|
||||
pub trait Foo {
|
||||
const X: EFoo;
|
||||
}
|
||||
|
||||
struct Abc;
|
||||
|
||||
impl Foo for Abc {
|
||||
const X: EFoo = EFoo::A;
|
||||
}
|
||||
|
||||
struct Def;
|
||||
impl Foo for Def {
|
||||
const X: EFoo = EFoo::A;
|
||||
}
|
||||
|
||||
pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
|
||||
//~^ ERROR associated consts cannot be referenced in patterns
|
||||
let A::X = arg;
|
||||
//~^ ERROR associated consts cannot be referenced in patterns
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,15 @@
|
||||
error[E0158]: associated consts cannot be referenced in patterns
|
||||
--> $DIR/issue-68393-let-pat-assoc-constant.rs:20:40
|
||||
|
|
||||
LL | pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
|
||||
| ^^^^
|
||||
|
||||
error[E0158]: associated consts cannot be referenced in patterns
|
||||
--> $DIR/issue-68393-let-pat-assoc-constant.rs:22:9
|
||||
|
|
||||
LL | let A::X = arg;
|
||||
| ^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0158`.
|
5
src/test/ui/pattern/issue-68394-let-pat-runtime-value.rs
Normal file
5
src/test/ui/pattern/issue-68394-let-pat-runtime-value.rs
Normal file
@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
let x = 255u8;
|
||||
let 0u8..=x = 0;
|
||||
//~^ ERROR runtime values cannot be referenced in patterns
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
error[E0080]: runtime values cannot be referenced in patterns
|
||||
--> $DIR/issue-68394-let-pat-runtime-value.rs:3:15
|
||||
|
|
||||
LL | let 0u8..=x = 0;
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
7
src/test/ui/pattern/issue-68396-let-float-bug.rs
Normal file
7
src/test/ui/pattern/issue-68396-let-float-bug.rs
Normal file
@ -0,0 +1,7 @@
|
||||
fn main() {
|
||||
let 1234567890123456789012345678901234567890e-340: f64 = 0.0;
|
||||
//~^ ERROR could not evaluate float literal (see issue #31407)
|
||||
|
||||
fn param(1234567890123456789012345678901234567890e-340: f64) {}
|
||||
//~^ ERROR could not evaluate float literal (see issue #31407)
|
||||
}
|
15
src/test/ui/pattern/issue-68396-let-float-bug.stderr
Normal file
15
src/test/ui/pattern/issue-68396-let-float-bug.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error[E0080]: could not evaluate float literal (see issue #31407)
|
||||
--> $DIR/issue-68396-let-float-bug.rs:2:9
|
||||
|
|
||||
LL | let 1234567890123456789012345678901234567890e-340: f64 = 0.0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0080]: could not evaluate float literal (see issue #31407)
|
||||
--> $DIR/issue-68396-let-float-bug.rs:5:14
|
||||
|
|
||||
LL | fn param(1234567890123456789012345678901234567890e-340: f64) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
@ -1,8 +1,10 @@
|
||||
error: unreachable pattern
|
||||
--> $DIR/struct-pattern-match-useless.rs:12:9
|
||||
|
|
||||
LL | Foo { x: _x, y: _y } => (),
|
||||
| -------------------- matches any value
|
||||
LL | Foo { .. } => ()
|
||||
| ^^^^^^^^^^
|
||||
| ^^^^^^^^^^ unreachable pattern
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/struct-pattern-match-useless.rs:1:9
|
||||
|
@ -1,8 +1,8 @@
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/feature-gate.rs:11:29
|
||||
error: fatal error triggered by #[rustc_error]
|
||||
--> $DIR/feature-gate.rs:16:1
|
||||
|
|
||||
LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
|
||||
| ^^^^^^^^
|
||||
LL | fn main() {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#![cfg_attr(gated, feature(const_trait_bound_opt_out))]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
trait T {
|
||||
const CONST: i32;
|
||||
@ -10,6 +11,6 @@ trait T {
|
||||
|
||||
const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
|
||||
//[stock]~^ ERROR `?const` on trait bounds is experimental
|
||||
//[stock,gated]~^^ ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn main() {}
|
||||
#[rustc_error]
|
||||
fn main() {} //[gated]~ ERROR fatal error triggered by #[rustc_error]
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0658]: `?const` on trait bounds is experimental
|
||||
--> $DIR/feature-gate.rs:11:29
|
||||
--> $DIR/feature-gate.rs:12:29
|
||||
|
|
||||
LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
|
||||
| ^^^^^^
|
||||
@ -7,12 +7,6 @@ LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/67794
|
||||
= help: add `#![feature(const_trait_bound_opt_out)]` to the crate attributes to enable
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/feature-gate.rs:11:29
|
||||
|
|
||||
LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -8,18 +8,14 @@ impl T for S {}
|
||||
|
||||
fn rpit() -> impl ?const T { S }
|
||||
//~^ ERROR `?const` is not permitted in `impl Trait`
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn apit(_: impl ?const T) {}
|
||||
//~^ ERROR `?const` is not permitted in `impl Trait`
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
|
||||
//~^ ERROR `?const` is not permitted in `impl Trait`
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
|
||||
//~^ ERROR `?const` is not permitted in `impl Trait`
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn main() {}
|
||||
|
@ -5,46 +5,22 @@ LL | fn rpit() -> impl ?const T { S }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` is not permitted in `impl Trait`
|
||||
--> $DIR/in-impl-trait.rs:13:17
|
||||
--> $DIR/in-impl-trait.rs:12:17
|
||||
|
|
||||
LL | fn apit(_: impl ?const T) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` is not permitted in `impl Trait`
|
||||
--> $DIR/in-impl-trait.rs:17:50
|
||||
--> $DIR/in-impl-trait.rs:15:50
|
||||
|
|
||||
LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` is not permitted in `impl Trait`
|
||||
--> $DIR/in-impl-trait.rs:21:48
|
||||
--> $DIR/in-impl-trait.rs:18:48
|
||||
|
|
||||
LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-impl-trait.rs:9:19
|
||||
|
|
||||
LL | fn rpit() -> impl ?const T { S }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-impl-trait.rs:13:17
|
||||
|
|
||||
LL | fn apit(_: impl ?const T) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-impl-trait.rs:17:50
|
||||
|
|
||||
LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-impl-trait.rs:21:48
|
||||
|
|
||||
LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -4,6 +4,5 @@
|
||||
trait Super {}
|
||||
trait T: ?const Super {}
|
||||
//~^ ERROR `?const` is not permitted in supertraits
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn main() {}
|
||||
|
@ -4,11 +4,5 @@ error: `?const` is not permitted in supertraits
|
||||
LL | trait T: ?const Super {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-trait-bounds.rs:5:10
|
||||
|
|
||||
LL | trait T: ?const Super {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -9,14 +9,11 @@ impl T for S {}
|
||||
// An inherent impl for the trait object `?const T`.
|
||||
impl ?const T {}
|
||||
//~^ ERROR `?const` is not permitted in trait objects
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn trait_object() -> &'static dyn ?const T { &S }
|
||||
//~^ ERROR `?const` is not permitted in trait objects
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
|
||||
//~^ ERROR `?const` is not permitted in trait objects
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn main() {}
|
||||
|
@ -5,34 +5,16 @@ LL | impl ?const T {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` is not permitted in trait objects
|
||||
--> $DIR/in-trait-object.rs:14:35
|
||||
--> $DIR/in-trait-object.rs:13:35
|
||||
|
|
||||
LL | fn trait_object() -> &'static dyn ?const T { &S }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` is not permitted in trait objects
|
||||
--> $DIR/in-trait-object.rs:18:61
|
||||
--> $DIR/in-trait-object.rs:16:61
|
||||
|
|
||||
LL | fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-trait-object.rs:10:6
|
||||
|
|
||||
LL | impl ?const T {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-trait-object.rs:14:35
|
||||
|
|
||||
LL | fn trait_object() -> &'static dyn ?const T { &S }
|
||||
| ^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/in-trait-object.rs:18:61
|
||||
|
|
||||
LL | fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -3,6 +3,5 @@
|
||||
|
||||
struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
|
||||
//~^ ERROR `?const` and `?` are mutually exclusive
|
||||
//~| ERROR `?const` on trait bounds is not yet implemented
|
||||
|
||||
fn main() {}
|
||||
|
@ -4,11 +4,5 @@ error: `?const` and `?` are mutually exclusive
|
||||
LL | struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: `?const` on trait bounds is not yet implemented
|
||||
--> $DIR/with-maybe-sized.rs:4:13
|
||||
|
|
||||
LL | struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
// compile-flags: -Z parse-only
|
||||
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_trait_bound_opt_out)]
|
||||
#![allow(incomplete_features)]
|
||||
@ -8,7 +6,12 @@
|
||||
struct S;
|
||||
trait T {}
|
||||
|
||||
impl const S {}
|
||||
//~^ ERROR inherent impls cannot be `const`
|
||||
//~| ERROR const trait impls are not yet implemented
|
||||
|
||||
impl const T {}
|
||||
//~^ ERROR `const` cannot modify an inherent impl
|
||||
//~^ ERROR inherent impls cannot be `const`
|
||||
//~| ERROR const trait impls are not yet implemented
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,10 +1,30 @@
|
||||
error: `const` cannot modify an inherent impl
|
||||
--> $DIR/inherent-impl.rs:11:6
|
||||
error: inherent impls cannot be `const`
|
||||
--> $DIR/inherent-impl.rs:9:1
|
||||
|
|
||||
LL | impl const S {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: only trait implementations may be annotated with `const`
|
||||
|
||||
error: inherent impls cannot be `const`
|
||||
--> $DIR/inherent-impl.rs:13:1
|
||||
|
|
||||
LL | impl const T {}
|
||||
| ^^^^^
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: only a trait impl can be `const`
|
||||
= note: only trait implementations may be annotated with `const`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: const trait impls are not yet implemented
|
||||
--> $DIR/inherent-impl.rs:9:1
|
||||
|
|
||||
LL | impl const S {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: const trait impls are not yet implemented
|
||||
--> $DIR/inherent-impl.rs:13:1
|
||||
|
|
||||
LL | impl const T {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const GRAPHVIZ_POSTFLOW_MSG: &'static str = "`borrowck_graphviz_postflow` attribute in test";
|
||||
const GRAPHVIZ_POSTFLOW_MSG: &str = "`borrowck_graphviz_postflow` attribute in test";
|
||||
|
||||
pub fn check(path: &Path, bad: &mut bool) {
|
||||
let test_dir: PathBuf = path.join("test");
|
||||
|
@ -53,7 +53,7 @@ fn extract_error_codes(f: &str, error_codes: &mut HashMap<String, bool>, path: &
|
||||
error_codes.insert(err_code.clone(), false);
|
||||
}
|
||||
// Now we extract the tests from the markdown file!
|
||||
let md = some_or_continue!(s.splitn(2, "include_str!(\"").skip(1).next());
|
||||
let md = some_or_continue!(s.splitn(2, "include_str!(\"").nth(1));
|
||||
let md_file_name = some_or_continue!(md.splitn(2, "\")").next());
|
||||
let path = some_or_continue!(path.parent()).join(md_file_name);
|
||||
match read_to_string(&path) {
|
||||
@ -84,7 +84,7 @@ fn extract_error_codes_from_tests(f: &str, error_codes: &mut HashMap<String, boo
|
||||
let s = line.trim();
|
||||
if s.starts_with("error[E") || s.starts_with("warning[E") {
|
||||
if let Some(err_code) = s.splitn(2, ']').next() {
|
||||
if let Some(err_code) = err_code.splitn(2, '[').skip(1).next() {
|
||||
if let Some(err_code) = err_code.splitn(2, '[').nth(1) {
|
||||
let nb = error_codes.entry(err_code.to_owned()).or_insert(false);
|
||||
*nb = true;
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
false
|
||||
}
|
||||
|
||||
pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
|
||||
@ -344,7 +344,7 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features
|
||||
}
|
||||
None
|
||||
} else {
|
||||
let s = issue_str.split('(').nth(1).unwrap().split(')').nth(0).unwrap();
|
||||
let s = issue_str.split('(').nth(1).unwrap().split(')').next().unwrap();
|
||||
Some(s.parse().unwrap())
|
||||
};
|
||||
Some((name.to_owned(), Feature { level, since, has_gate_test: false, tracking_issue }))
|
||||
|
@ -38,7 +38,7 @@ impl FromStr for Version {
|
||||
|
||||
let parts = [part()?, part()?, part()?];
|
||||
|
||||
if let Some(_) = iter.next() {
|
||||
if iter.next().is_some() {
|
||||
// Ensure we don't have more than 3 parts.
|
||||
return Err(ParseVersionError::WrongNumberOfParts);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ enum LIUState {
|
||||
fn line_is_url(columns: usize, line: &str) -> bool {
|
||||
// more basic check for error_codes.rs, to avoid complexity in implementing two state machines
|
||||
if columns == ERROR_CODE_COLS {
|
||||
return line.starts_with("[") && line.contains("]:") && line.contains("http");
|
||||
return line.starts_with('[') && line.contains("]:") && line.contains("http");
|
||||
}
|
||||
|
||||
use self::LIUState::*;
|
||||
|
Loading…
Reference in New Issue
Block a user