Auto merge of #72330 - Dylan-DPC:rollup-yuxadv8, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #71599 (Support coercion between (FnDef | Closure) and (FnDef | Closure)) - #71973 (Lazy normalization of constants (Reprise)) - #72283 (Drop Elaboration Elaboration) - #72290 (Add newer rust versions to linker-plugin-lto.md) - #72318 (Add help text for remote-test-client) Failed merges: r? @ghost
This commit is contained in:
commit
89988fe727
73 changed files with 1342 additions and 215 deletions
|
@ -100,11 +100,17 @@ LLVM. However, the approximation is usually reliable.
|
|||
|
||||
The following table shows known good combinations of toolchain versions.
|
||||
|
||||
| | Clang 7 | Clang 8 |
|
||||
|-----------|-----------|-----------|
|
||||
| Rust 1.34 | ✗ | ✓ |
|
||||
| Rust 1.35 | ✗ | ✓ |
|
||||
| Rust 1.36 | ✗ | ✓ |
|
||||
| Rust 1.37 | ✗ | ✓ |
|
||||
| | Clang 7 | Clang 8 | Clang 9 |
|
||||
|-----------|-----------|-----------|-----------|
|
||||
| Rust 1.34 | ✗ | ✓ | ✗ |
|
||||
| Rust 1.35 | ✗ | ✓ | ✗ |
|
||||
| Rust 1.36 | ✗ | ✓ | ✗ |
|
||||
| Rust 1.37 | ✗ | ✓ | ✗ |
|
||||
| Rust 1.38 | ✗ | ✗ | ✓ |
|
||||
| Rust 1.39 | ✗ | ✗ | ✓ |
|
||||
| Rust 1.40 | ✗ | ✗ | ✓ |
|
||||
| Rust 1.41 | ✗ | ✗ | ✓ |
|
||||
| Rust 1.42 | ✗ | ✗ | ✓ |
|
||||
| Rust 1.43 | ✗ | ✗ | ✓ |
|
||||
|
||||
Note that the compatibility policy for this feature might change in the future.
|
||||
|
|
|
@ -25,7 +25,7 @@ use rustc_middle::arena::ArenaAllocatable;
|
|||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
|
||||
use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, BoundVar, Const, Ty, TyCtxt};
|
||||
use std::fmt::Debug;
|
||||
|
||||
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||
|
@ -671,6 +671,13 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {
|
||||
span_bug!(
|
||||
self.cause.span(self.infcx.tcx),
|
||||
"lazy_normalization_consts: unreachable `const_equate`"
|
||||
);
|
||||
}
|
||||
|
||||
fn normalization() -> NormalizationStrategy {
|
||||
NormalizationStrategy::Eager
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_middle::ty::{IntType, UintType};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
|
@ -126,7 +126,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||
b: &'tcx ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>
|
||||
where
|
||||
R: TypeRelation<'tcx>,
|
||||
R: ConstEquateRelation<'tcx>,
|
||||
{
|
||||
debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
|
||||
if a == b {
|
||||
|
@ -164,7 +164,22 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
|
|||
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
|
||||
return self.unify_const_variable(!a_is_expected, vid, a);
|
||||
}
|
||||
|
||||
(ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => {
|
||||
// FIXME(#59490): Need to remove the leak check to accomodate
|
||||
// escaping bound variables here.
|
||||
if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
|
||||
relation.const_equate_obligation(a, b);
|
||||
}
|
||||
return Ok(b);
|
||||
}
|
||||
(_, ty::ConstKind::Unevaluated(..)) if self.tcx.lazy_normalization() => {
|
||||
// FIXME(#59490): Need to remove the leak check to accomodate
|
||||
// escaping bound variables here.
|
||||
if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
|
||||
relation.const_equate_obligation(a, b);
|
||||
}
|
||||
return Ok(a);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -375,6 +390,20 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf);
|
||||
Ok(Generalization { ty, needs_wf })
|
||||
}
|
||||
|
||||
pub fn add_const_equate_obligation(
|
||||
&mut self,
|
||||
a_is_expected: bool,
|
||||
a: &'tcx ty::Const<'tcx>,
|
||||
b: &'tcx ty::Const<'tcx>,
|
||||
) {
|
||||
let predicate = if a_is_expected {
|
||||
ty::Predicate::ConstEquate(a, b)
|
||||
} else {
|
||||
ty::Predicate::ConstEquate(b, a)
|
||||
};
|
||||
self.obligations.push(Obligation::new(self.trace.cause.clone(), self.param_env, predicate));
|
||||
}
|
||||
}
|
||||
|
||||
struct Generalizer<'cx, 'tcx> {
|
||||
|
@ -637,11 +666,19 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(c),
|
||||
_ => relate::super_relate_consts(self, c, c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> {
|
||||
/// Register an obligation that both constants must be equal to each other.
|
||||
///
|
||||
/// If they aren't equal then the relation doesn't hold.
|
||||
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
|
||||
}
|
||||
|
||||
pub trait RelateResultCompare<'tcx, T> {
|
||||
fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T>
|
||||
where
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::combine::{CombineFields, RelationDir};
|
||||
use super::combine::{CombineFields, ConstEquateRelation, RelationDir};
|
||||
use super::Subtype;
|
||||
|
||||
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
|
||||
|
@ -140,3 +140,9 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstEquateRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
||||
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use super::lattice::{self, LatticeDir};
|
|||
use super::InferCtxt;
|
||||
use super::Subtype;
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::traits::ObligationCause;
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
@ -116,3 +117,9 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use super::lattice::{self, LatticeDir};
|
|||
use super::InferCtxt;
|
||||
use super::Subtype;
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::traits::ObligationCause;
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
@ -100,6 +101,12 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> {
|
||||
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> {
|
||||
fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> {
|
||||
self.fields.infcx
|
||||
|
|
|
@ -1490,6 +1490,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
self.report_and_explain_type_error(trace, &err)
|
||||
}
|
||||
|
||||
pub fn report_mismatched_consts(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
expected: &'tcx ty::Const<'tcx>,
|
||||
actual: &'tcx ty::Const<'tcx>,
|
||||
err: TypeError<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let trace = TypeTrace::consts(cause, true, expected, actual);
|
||||
self.report_and_explain_type_error(trace, &err)
|
||||
}
|
||||
|
||||
pub fn replace_bound_vars_with_fresh_vars<T>(
|
||||
&self,
|
||||
span: Span,
|
||||
|
@ -1777,6 +1788,15 @@ impl<'tcx> TypeTrace<'tcx> {
|
|||
TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
|
||||
}
|
||||
|
||||
pub fn consts(
|
||||
cause: &ObligationCause<'tcx>,
|
||||
a_is_expected: bool,
|
||||
a: &'tcx ty::Const<'tcx>,
|
||||
b: &'tcx ty::Const<'tcx>,
|
||||
) -> TypeTrace<'tcx> {
|
||||
TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) }
|
||||
}
|
||||
|
||||
pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> {
|
||||
TypeTrace {
|
||||
cause: ObligationCause::dummy(),
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
//! thing we relate in chalk are basically domain goals and their
|
||||
//! constituents)
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::{ConstVarValue, ConstVariableValue};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
@ -77,6 +78,8 @@ pub trait TypeRelatingDelegate<'tcx> {
|
|||
/// delegate.
|
||||
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
|
||||
|
||||
fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
|
||||
|
||||
/// Creates a new universe index. Used when instantiating placeholders.
|
||||
fn create_next_universe(&mut self) -> ty::UniverseIndex;
|
||||
|
||||
|
@ -715,6 +718,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D>
|
||||
where
|
||||
D: TypeRelatingDelegate<'tcx>,
|
||||
{
|
||||
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
|
||||
self.delegate.const_equate(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/// When we encounter a binder like `for<..> fn(..)`, we actually have
|
||||
/// to walk the `fn` value to find all the values bound by the `for`
|
||||
/// (these are not explicitly present in the ty representation right
|
||||
|
@ -976,6 +988,7 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(a),
|
||||
_ => relate::super_relate_consts(self, a, a),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ pub fn explicit_outlives_bounds<'tcx>(
|
|||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::TypeOutlives(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => None,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => None,
|
||||
ty::Predicate::RegionOutlives(ref data) => data
|
||||
.no_bound_vars()
|
||||
.map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::combine::{CombineFields, RelationDir};
|
||||
use super::SubregionOrigin;
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::traits::Obligation;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
|
||||
|
@ -169,3 +170,9 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> {
|
|||
self.fields.higher_ranked_sub(a, b, self.a_is_expected)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstEquateRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
||||
fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
|
||||
self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ pub mod util;
|
|||
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, Const, Ty};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub use self::FulfillmentErrorCode::*;
|
||||
|
@ -81,6 +81,7 @@ pub enum FulfillmentErrorCode<'tcx> {
|
|||
CodeSelectionError(SelectionError<'tcx>),
|
||||
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
|
||||
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
|
||||
CodeConstEquateError(ExpectedFound<&'tcx Const<'tcx>>, TypeError<'tcx>),
|
||||
CodeAmbiguity,
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
|
|||
super::CodeSubtypeError(ref a, ref b) => {
|
||||
write!(f, "CodeSubtypeError({:?}, {:?})", a, b)
|
||||
}
|
||||
super::CodeConstEquateError(ref a, ref b) => {
|
||||
write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
|
||||
}
|
||||
super::CodeAmbiguity => write!(f, "Ambiguity"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ pub fn anonymize_predicate<'tcx>(
|
|||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs)
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEquate(c1, c2) => ty::Predicate::ConstEquate(c1, c2),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,6 +189,10 @@ impl Elaborator<'tcx> {
|
|||
// Currently, we do not elaborate const-evaluatable
|
||||
// predicates.
|
||||
}
|
||||
ty::Predicate::ConstEquate(..) => {
|
||||
// Currently, we do not elaborate const-equate
|
||||
// predicates.
|
||||
}
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
// Nothing to elaborate from `'a: 'b`.
|
||||
}
|
||||
|
|
|
@ -1221,7 +1221,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
|
|||
ObjectSafe(..) |
|
||||
ClosureKind(..) |
|
||||
Subtype(..) |
|
||||
ConstEvaluatable(..) => continue,
|
||||
ConstEvaluatable(..) |
|
||||
ConstEquate(..) => continue,
|
||||
};
|
||||
if predicate.is_global() {
|
||||
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
|
||||
|
|
|
@ -1339,7 +1339,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
/// What mode(s) of borrowck should we run? AST? MIR? both?
|
||||
/// (Also considers the `#![feature(nll)]` setting.)
|
||||
pub fn borrowck_mode(&self) -> BorrowckMode {
|
||||
pub fn borrowck_mode(self) -> BorrowckMode {
|
||||
// Here are the main constraints we need to deal with:
|
||||
//
|
||||
// 1. An opts.borrowck_mode of `BorrowckMode::Migrate` is
|
||||
|
@ -1369,6 +1369,13 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.sess.opts.borrowck_mode
|
||||
}
|
||||
|
||||
/// If `true`, we should use lazy normalization for constants, otherwise
|
||||
/// we still evaluate them eagerly.
|
||||
#[inline]
|
||||
pub fn lazy_normalization(self) -> bool {
|
||||
self.features().const_generics
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn local_crate_exports_generics(self) -> bool {
|
||||
debug_assert!(self.sess.opts.share_generics());
|
||||
|
@ -2069,24 +2076,25 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }))
|
||||
}
|
||||
|
||||
/// Given a closure signature `sig`, returns an equivalent `fn`
|
||||
/// type with the same signature. Detuples and so forth -- so
|
||||
/// e.g., if we have a sig with `Fn<(u32, i32)>` then you would get
|
||||
/// a `fn(u32, i32)`.
|
||||
/// `unsafety` determines the unsafety of the `fn` type. If you pass
|
||||
/// Given a closure signature, returns an equivalent fn signature. Detuples
|
||||
/// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then
|
||||
/// you would get a `fn(u32, i32)`.
|
||||
/// `unsafety` determines the unsafety of the fn signature. If you pass
|
||||
/// `hir::Unsafety::Unsafe` in the previous example, then you would get
|
||||
/// an `unsafe fn (u32, i32)`.
|
||||
/// It cannot convert a closure that requires unsafe.
|
||||
pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>, unsafety: hir::Unsafety) -> Ty<'tcx> {
|
||||
let converted_sig = sig.map_bound(|s| {
|
||||
pub fn signature_unclosure(
|
||||
self,
|
||||
sig: PolyFnSig<'tcx>,
|
||||
unsafety: hir::Unsafety,
|
||||
) -> PolyFnSig<'tcx> {
|
||||
sig.map_bound(|s| {
|
||||
let params_iter = match s.inputs()[0].kind {
|
||||
ty::Tuple(params) => params.into_iter().map(|k| k.expect_ty()),
|
||||
_ => bug!(),
|
||||
};
|
||||
self.mk_fn_sig(params_iter, s.output(), s.c_variadic, unsafety, abi::Abi::Rust)
|
||||
});
|
||||
|
||||
self.mk_fn_ptr(converted_sig)
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
|
|
|
@ -1054,6 +1054,9 @@ pub enum Predicate<'tcx> {
|
|||
|
||||
/// Constant initializer must evaluate successfully.
|
||||
ConstEvaluatable(DefId, SubstsRef<'tcx>),
|
||||
|
||||
/// Constants must be equal. The first component is the const that is expected.
|
||||
ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
|
||||
}
|
||||
|
||||
/// The crate outlives map is computed during typeck and contains the
|
||||
|
@ -1172,6 +1175,9 @@ impl<'tcx> Predicate<'tcx> {
|
|||
Predicate::ConstEvaluatable(def_id, const_substs) => {
|
||||
Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs))
|
||||
}
|
||||
Predicate::ConstEquate(c1, c2) => {
|
||||
Predicate::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1349,7 +1355,8 @@ impl<'tcx> Predicate<'tcx> {
|
|||
| Predicate::ObjectSafe(..)
|
||||
| Predicate::ClosureKind(..)
|
||||
| Predicate::TypeOutlives(..)
|
||||
| Predicate::ConstEvaluatable(..) => None,
|
||||
| Predicate::ConstEvaluatable(..)
|
||||
| Predicate::ConstEquate(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1363,7 +1370,8 @@ impl<'tcx> Predicate<'tcx> {
|
|||
| Predicate::WellFormed(..)
|
||||
| Predicate::ObjectSafe(..)
|
||||
| Predicate::ClosureKind(..)
|
||||
| Predicate::ConstEvaluatable(..) => None,
|
||||
| Predicate::ConstEvaluatable(..)
|
||||
| Predicate::ConstEquate(..) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,11 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
|
|||
}
|
||||
}
|
||||
|
||||
ty::Array(element, _) => {
|
||||
// Don't look into the len const as it doesn't affect regions
|
||||
compute_components(tcx, element, out);
|
||||
}
|
||||
|
||||
ty::Closure(_, ref substs) => {
|
||||
for upvar_ty in substs.as_closure().upvar_tys() {
|
||||
compute_components(tcx, upvar_ty, out);
|
||||
|
@ -158,7 +163,6 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo
|
|||
ty::Opaque(..) | // OutlivesNominalType (ish)
|
||||
ty::Foreign(..) | // OutlivesNominalType
|
||||
ty::Str | // OutlivesScalar (ish)
|
||||
ty::Array(..) | // ...
|
||||
ty::Slice(..) | // ...
|
||||
ty::RawPtr(..) | // ...
|
||||
ty::Ref(..) | // OutlivesReference
|
||||
|
|
|
@ -2058,6 +2058,13 @@ define_print_and_forward_display! {
|
|||
print_value_path(def_id, substs),
|
||||
write("` can be evaluated"))
|
||||
}
|
||||
ty::Predicate::ConstEquate(c1, c2) => {
|
||||
p!(write("the constant `"),
|
||||
print(c1),
|
||||
write("` equals `"),
|
||||
print(c2),
|
||||
write("`"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -431,6 +431,9 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
|
|||
let t = relation.relate(&a_t, &b_t)?;
|
||||
match relation.relate(&sz_a, &sz_b) {
|
||||
Ok(sz) => Ok(tcx.mk_ty(ty::Array(t, sz))),
|
||||
// FIXME(#72219) Implement improved diagnostics for mismatched array
|
||||
// length?
|
||||
Err(err) if relation.tcx().lazy_normalization() => Err(err),
|
||||
Err(err) => {
|
||||
// Check whether the lengths are both concrete/known values,
|
||||
// but are unequal, for better diagnostics.
|
||||
|
|
|
@ -240,6 +240,7 @@ impl fmt::Debug for ty::Predicate<'tcx> {
|
|||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
|
||||
}
|
||||
ty::Predicate::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -492,6 +493,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> {
|
|||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
tcx.lift(&substs).map(|substs| ty::Predicate::ConstEvaluatable(def_id, substs))
|
||||
}
|
||||
ty::Predicate::ConstEquate(c1, c2) => {
|
||||
tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::Predicate::ConstEquate(c1, c2))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2088,7 +2088,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
ty::Closure(_, substs) => substs.as_closure().sig(),
|
||||
_ => bug!(),
|
||||
};
|
||||
let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig, *unsafety);
|
||||
let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety));
|
||||
|
||||
if let Err(terr) = self.eq_types(
|
||||
ty_fn_ptr_from,
|
||||
|
|
|
@ -2,7 +2,7 @@ use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRe
|
|||
use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, Const, Ty};
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
|
||||
use crate::borrow_check::constraints::OutlivesConstraint;
|
||||
|
@ -99,6 +99,10 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// We don't have to worry about the equality of consts during borrow checking
|
||||
// as consts always have a static lifetime.
|
||||
fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {}
|
||||
|
||||
fn normalization() -> NormalizationStrategy {
|
||||
NormalizationStrategy::Eager
|
||||
}
|
||||
|
|
|
@ -277,7 +277,18 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
|
||||
if let DropFlagMode::Shallow = mode { DropStyle::Static } else { DropStyle::Open }
|
||||
match mode {
|
||||
DropFlagMode::Shallow => {
|
||||
// Drops for the contained fields are "shallow" and "static" - they will simply call
|
||||
// the field's own drop glue.
|
||||
DropStyle::Static
|
||||
}
|
||||
DropFlagMode::Deep => {
|
||||
// The top-level drop is "deep" and "open" - it will be elaborated to a drop ladder
|
||||
// dropping each field contained in the value.
|
||||
DropStyle::Open
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_drop_flag(&mut self, _path: Self::Path) -> Option<Operand<'tcx>> {
|
||||
|
|
|
@ -28,7 +28,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -
|
|||
| Predicate::TypeOutlives(_)
|
||||
| Predicate::WellFormed(_)
|
||||
| Predicate::Projection(_)
|
||||
| Predicate::ConstEvaluatable(..) => continue,
|
||||
| Predicate::ConstEvaluatable(..)
|
||||
| Predicate::ConstEquate(..) => continue,
|
||||
Predicate::ObjectSafe(_) => {
|
||||
bug!("object safe predicate on function: {:#?}", predicate)
|
||||
}
|
||||
|
|
|
@ -12,10 +12,15 @@ use std::fmt;
|
|||
|
||||
use std::convert::TryInto;
|
||||
|
||||
/// The value of an inserted drop flag.
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum DropFlagState {
|
||||
Present, // i.e., initialized
|
||||
Absent, // i.e., deinitialized or "moved"
|
||||
/// The tracked value is initialized and needs to be dropped when leaving its scope.
|
||||
Present,
|
||||
|
||||
/// The tracked value is uninitialized or was moved out of and does not need to be dropped when
|
||||
/// leaving its scope.
|
||||
Absent,
|
||||
}
|
||||
|
||||
impl DropFlagState {
|
||||
|
@ -27,23 +32,42 @@ impl DropFlagState {
|
|||
}
|
||||
}
|
||||
|
||||
/// Describes how/if a value should be dropped.
|
||||
#[derive(Debug)]
|
||||
pub enum DropStyle {
|
||||
/// The value is already dead at the drop location, no drop will be executed.
|
||||
Dead,
|
||||
|
||||
/// The value is known to always be initialized at the drop location, drop will always be
|
||||
/// executed.
|
||||
Static,
|
||||
|
||||
/// Whether the value needs to be dropped depends on its drop flag.
|
||||
Conditional,
|
||||
|
||||
/// An "open" drop is one where only the fields of a value are dropped.
|
||||
///
|
||||
/// For example, this happens when moving out of a struct field: The rest of the struct will be
|
||||
/// dropped in such an "open" drop. It is also used to generate drop glue for the individual
|
||||
/// components of a value, for example for dropping array elements.
|
||||
Open,
|
||||
}
|
||||
|
||||
/// Which drop flags to affect/check with an operation.
|
||||
#[derive(Debug)]
|
||||
pub enum DropFlagMode {
|
||||
/// Only affect the top-level drop flag, not that of any contained fields.
|
||||
Shallow,
|
||||
/// Affect all nested drop flags in addition to the top-level one.
|
||||
Deep,
|
||||
}
|
||||
|
||||
/// Describes if unwinding is necessary and where to unwind to if a panic occurs.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Unwind {
|
||||
/// Unwind to this block.
|
||||
To(BasicBlock),
|
||||
/// Already in an unwind path, any panic will cause an abort.
|
||||
InCleanup,
|
||||
}
|
||||
|
||||
|
@ -74,20 +98,58 @@ impl Unwind {
|
|||
}
|
||||
|
||||
pub trait DropElaborator<'a, 'tcx>: fmt::Debug {
|
||||
/// The type representing paths that can be moved out of.
|
||||
///
|
||||
/// Users can move out of individual fields of a struct, such as `a.b.c`. This type is used to
|
||||
/// represent such move paths. Sometimes tracking individual move paths is not necessary, in
|
||||
/// which case this may be set to (for example) `()`.
|
||||
type Path: Copy + fmt::Debug;
|
||||
|
||||
// Accessors
|
||||
|
||||
fn patch(&mut self) -> &mut MirPatch<'tcx>;
|
||||
fn body(&self) -> &'a Body<'tcx>;
|
||||
fn tcx(&self) -> TyCtxt<'tcx>;
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx>;
|
||||
|
||||
// Drop logic
|
||||
|
||||
/// Returns how `path` should be dropped, given `mode`.
|
||||
fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle;
|
||||
|
||||
/// Returns the drop flag of `path` as a MIR `Operand` (or `None` if `path` has no drop flag).
|
||||
fn get_drop_flag(&mut self, path: Self::Path) -> Option<Operand<'tcx>>;
|
||||
|
||||
/// Modifies the MIR patch so that the drop flag of `path` (if any) is cleared at `location`.
|
||||
///
|
||||
/// If `mode` is deep, drop flags of all child paths should also be cleared by inserting
|
||||
/// additional statements.
|
||||
fn clear_drop_flag(&mut self, location: Location, path: Self::Path, mode: DropFlagMode);
|
||||
|
||||
// Subpaths
|
||||
|
||||
/// Returns the subpath of a field of `path` (or `None` if there is no dedicated subpath).
|
||||
///
|
||||
/// If this returns `None`, `field` will not get a dedicated drop flag.
|
||||
fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path>;
|
||||
|
||||
/// Returns the subpath of a dereference of `path` (or `None` if there is no dedicated subpath).
|
||||
///
|
||||
/// If this returns `None`, `*path` will not get a dedicated drop flag.
|
||||
///
|
||||
/// This is only relevant for `Box<T>`, where the contained `T` can be moved out of the box.
|
||||
fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path>;
|
||||
|
||||
/// Returns the subpath of downcasting `path` to one of its variants.
|
||||
///
|
||||
/// If this returns `None`, the downcast of `path` will not get a dedicated drop flag.
|
||||
fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path>;
|
||||
|
||||
/// Returns the subpath of indexing a fixed-size array `path`.
|
||||
///
|
||||
/// If this returns `None`, elements of `path` will not get a dedicated drop flag.
|
||||
///
|
||||
/// This is only relevant for array patterns, which can move out of individual array elements.
|
||||
fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path>;
|
||||
}
|
||||
|
||||
|
@ -106,6 +168,14 @@ where
|
|||
unwind: Unwind,
|
||||
}
|
||||
|
||||
/// "Elaborates" a drop of `place`/`path` and patches `bb`'s terminator to execute it.
|
||||
///
|
||||
/// The passed `elaborator` is used to determine what should happen at the drop terminator. It
|
||||
/// decides whether the drop can be statically determined or whether it needs a dynamic drop flag,
|
||||
/// and whether the drop is "open", ie. should be expanded to drop all subfields of the dropped
|
||||
/// value.
|
||||
///
|
||||
/// When this returns, the MIR patch in the `elaborator` contains the necessary changes.
|
||||
pub fn elaborate_drop<'b, 'tcx, D>(
|
||||
elaborator: &mut D,
|
||||
source_info: SourceInfo,
|
||||
|
@ -346,9 +416,7 @@ where
|
|||
let interior = self.tcx().mk_place_deref(self.place);
|
||||
let interior_path = self.elaborator.deref_subpath(self.path);
|
||||
|
||||
let succ = self.succ; // FIXME(#43234)
|
||||
let unwind = self.unwind;
|
||||
let succ = self.box_free_block(adt, substs, succ, unwind);
|
||||
let succ = self.box_free_block(adt, substs, self.succ, self.unwind);
|
||||
let unwind_succ =
|
||||
self.unwind.map(|unwind| self.box_free_block(adt, substs, unwind, Unwind::InCleanup));
|
||||
|
||||
|
@ -829,6 +897,8 @@ where
|
|||
self.drop_flag_test_block(drop_block, succ, unwind)
|
||||
}
|
||||
|
||||
/// Creates a block that resets the drop flag. If `mode` is deep, all children drop flags will
|
||||
/// also be cleared.
|
||||
fn drop_flag_reset_block(
|
||||
&mut self,
|
||||
mode: DropFlagMode,
|
||||
|
@ -850,13 +920,15 @@ where
|
|||
|
||||
fn elaborated_drop_block(&mut self) -> BasicBlock {
|
||||
debug!("elaborated_drop_block({:?})", self);
|
||||
let unwind = self.unwind; // FIXME(#43234)
|
||||
let succ = self.succ;
|
||||
let blk = self.drop_block(succ, unwind);
|
||||
let blk = self.drop_block(self.succ, self.unwind);
|
||||
self.elaborate_drop(blk);
|
||||
blk
|
||||
}
|
||||
|
||||
/// Creates a block that frees the backing memory of a `Box` if its drop is required (either
|
||||
/// statically or by checking its drop flag).
|
||||
///
|
||||
/// The contained value will not be dropped.
|
||||
fn box_free_block(
|
||||
&mut self,
|
||||
adt: &'tcx ty::AdtDef,
|
||||
|
@ -868,6 +940,8 @@ where
|
|||
self.drop_flag_test_block(block, target, unwind)
|
||||
}
|
||||
|
||||
/// Creates a block that frees the backing memory of a `Box` (without dropping the contained
|
||||
/// value).
|
||||
fn unelaborated_free_block(
|
||||
&mut self,
|
||||
adt: &'tcx ty::AdtDef,
|
||||
|
@ -914,6 +988,11 @@ where
|
|||
self.new_block(unwind, block)
|
||||
}
|
||||
|
||||
/// Returns the block to jump to in order to test the drop flag and execute the drop.
|
||||
///
|
||||
/// Depending on the required `DropStyle`, this might be a generated block with an `if`
|
||||
/// terminator (for dynamic/open drops), or it might be `on_set` or `on_unset` itself, in case
|
||||
/// the drop can be statically determined.
|
||||
fn drop_flag_test_block(
|
||||
&mut self,
|
||||
on_set: BasicBlock,
|
||||
|
|
|
@ -1277,7 +1277,8 @@ crate fn required_region_bounds(
|
|||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::RegionOutlives(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => None,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => None,
|
||||
ty::Predicate::TypeOutlives(predicate) => {
|
||||
// Search for a bound of the form `erased_self_ty
|
||||
// : 'a`, but be wary of something like `for<'a>
|
||||
|
|
|
@ -615,6 +615,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
obligation
|
||||
)
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEquate(..) => {
|
||||
// Errors for `ConstEquate` predicates show up as
|
||||
// `SelectionError::ConstEvalFailure`,
|
||||
// not `Unimplemented`.
|
||||
span_bug!(
|
||||
span,
|
||||
"const-equate requirement gave wrong error: `{:?}`",
|
||||
obligation
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1092,6 +1103,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
)
|
||||
.emit();
|
||||
}
|
||||
FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => {
|
||||
self.report_mismatched_consts(
|
||||
&error.obligation.cause,
|
||||
expected_found.expected,
|
||||
expected_found.found,
|
||||
err.clone(),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,11 @@ use crate::infer::{InferCtxt, TyOrConstInferVar};
|
|||
use rustc_data_structures::obligation_forest::ProcessResult;
|
||||
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
|
||||
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::error::ExpectedFound;
|
||||
use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeFoldable};
|
||||
use rustc_middle::ty::{self, Const, ToPolyTraitRef, Ty, TypeFoldable};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::project;
|
||||
|
@ -520,6 +522,68 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||
Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))),
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEquate(c1, c2) => {
|
||||
debug!("equating consts: c1={:?} c2={:?}", c1, c2);
|
||||
|
||||
let stalled_on = &mut pending_obligation.stalled_on;
|
||||
|
||||
let mut evaluate = |c: &'tcx Const<'tcx>| {
|
||||
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
|
||||
match self.selcx.infcx().const_eval_resolve(
|
||||
obligation.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
promoted,
|
||||
Some(obligation.cause.span),
|
||||
) {
|
||||
Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty)),
|
||||
Err(ErrorHandled::TooGeneric) => {
|
||||
stalled_on.append(
|
||||
&mut substs
|
||||
.types()
|
||||
.filter_map(|ty| TyOrConstInferVar::maybe_from_ty(ty))
|
||||
.collect(),
|
||||
);
|
||||
Err(ErrorHandled::TooGeneric)
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
} else {
|
||||
Ok(c)
|
||||
}
|
||||
};
|
||||
|
||||
match (evaluate(c1), evaluate(c2)) {
|
||||
(Ok(c1), Ok(c2)) => {
|
||||
match self
|
||||
.selcx
|
||||
.infcx()
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(c1, c2)
|
||||
{
|
||||
Ok(_) => ProcessResult::Changed(vec![]),
|
||||
Err(err) => {
|
||||
ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError(
|
||||
ExpectedFound::new(true, c1, c2),
|
||||
err,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
(Err(ErrorHandled::Reported(ErrorReported)), _)
|
||||
| (_, Err(ErrorHandled::Reported(ErrorReported))) => ProcessResult::Error(
|
||||
CodeSelectionError(ConstEvalFailure(ErrorHandled::Reported(ErrorReported))),
|
||||
),
|
||||
(Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!(
|
||||
obligation.cause.span(self.selcx.tcx()),
|
||||
"ConstEquate: const_eval_resolve returned an unexpected error"
|
||||
),
|
||||
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
|
||||
ProcessResult::Unchanged
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,9 @@ use crate::traits::{self, Obligation, ObligationCause};
|
|||
use rustc_errors::{Applicability, FatalError};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
|
||||
use rustc_middle::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstness};
|
||||
use rustc_middle::ty::{Predicate, ToPredicate};
|
||||
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
|
@ -281,7 +282,8 @@ fn predicates_reference_self(
|
|||
| ty::Predicate::RegionOutlives(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::Subtype(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => None,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => None,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
@ -313,7 +315,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::TypeOutlives(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => false,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => false,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -724,51 +727,65 @@ fn contains_illegal_self_type_reference<'tcx>(
|
|||
// object type, and we cannot resolve `Self as SomeOtherTrait`
|
||||
// without knowing what `Self` is.
|
||||
|
||||
let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
|
||||
let self_ty = tcx.types.self_param;
|
||||
struct IllegalSelfTypeVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
trait_def_id: DefId,
|
||||
supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>>,
|
||||
}
|
||||
|
||||
let mut walker = ty.walk();
|
||||
while let Some(arg) = walker.next() {
|
||||
if arg == self_ty.into() {
|
||||
return true;
|
||||
}
|
||||
impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
match t.kind {
|
||||
ty::Param(_) => t == self.self_ty,
|
||||
ty::Projection(ref data) => {
|
||||
// This is a projected type `<Foo as SomeTrait>::X`.
|
||||
|
||||
// Special-case projections (everything else is walked normally).
|
||||
if let GenericArgKind::Type(ty) = arg.unpack() {
|
||||
if let ty::Projection(ref data) = ty.kind {
|
||||
// This is a projected type `<Foo as SomeTrait>::X`.
|
||||
// Compute supertraits of current trait lazily.
|
||||
if self.supertraits.is_none() {
|
||||
let trait_ref =
|
||||
ty::Binder::bind(ty::TraitRef::identity(self.tcx, self.trait_def_id));
|
||||
self.supertraits = Some(traits::supertraits(self.tcx, trait_ref).collect());
|
||||
}
|
||||
|
||||
// Compute supertraits of current trait lazily.
|
||||
if supertraits.is_none() {
|
||||
let trait_ref = ty::Binder::bind(ty::TraitRef::identity(tcx, trait_def_id));
|
||||
supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
|
||||
// Determine whether the trait reference `Foo as
|
||||
// SomeTrait` is in fact a supertrait of the
|
||||
// current trait. In that case, this type is
|
||||
// legal, because the type `X` will be specified
|
||||
// in the object type. Note that we can just use
|
||||
// direct equality here because all of these types
|
||||
// are part of the formal parameter listing, and
|
||||
// hence there should be no inference variables.
|
||||
let projection_trait_ref = ty::Binder::bind(data.trait_ref(self.tcx));
|
||||
let is_supertrait_of_current_trait =
|
||||
self.supertraits.as_ref().unwrap().contains(&projection_trait_ref);
|
||||
|
||||
if is_supertrait_of_current_trait {
|
||||
false // do not walk contained types, do not report error, do collect $200
|
||||
} else {
|
||||
t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
|
||||
}
|
||||
}
|
||||
|
||||
// Determine whether the trait reference `Foo as
|
||||
// SomeTrait` is in fact a supertrait of the
|
||||
// current trait. In that case, this type is
|
||||
// legal, because the type `X` will be specified
|
||||
// in the object type. Note that we can just use
|
||||
// direct equality here because all of these types
|
||||
// are part of the formal parameter listing, and
|
||||
// hence there should be no inference variables.
|
||||
let projection_trait_ref = ty::Binder::bind(data.trait_ref(tcx));
|
||||
let is_supertrait_of_current_trait =
|
||||
supertraits.as_ref().unwrap().contains(&projection_trait_ref);
|
||||
|
||||
if is_supertrait_of_current_trait {
|
||||
// Do not walk contained types, do not report error, do collect $200.
|
||||
walker.skip_current_subtree();
|
||||
}
|
||||
|
||||
// DO walk contained types, POSSIBLY reporting an error.
|
||||
_ => t.super_visit_with(self), // walk contained types, if any
|
||||
}
|
||||
}
|
||||
|
||||
// Walk contained types, if any.
|
||||
fn visit_const(&mut self, _c: &ty::Const<'tcx>) -> bool {
|
||||
// FIXME(#72219) Look into the unevaluated constants for object safety violations.
|
||||
// Do not walk substitutions of unevaluated consts, as they contain `Self`, even
|
||||
// though the const expression doesn't necessary use it. Currently type variables
|
||||
// inside array length expressions are forbidden, so they can't break the above
|
||||
// rules.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
ty.visit_with(&mut IllegalSelfTypeVisitor {
|
||||
tcx,
|
||||
self_ty: tcx.types.self_param,
|
||||
trait_def_id,
|
||||
supertraits: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
||||
|
|
|
@ -388,8 +388,12 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
|
|||
}
|
||||
|
||||
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
let constant = constant.super_fold_with(self);
|
||||
constant.eval(self.selcx.tcx(), self.param_env)
|
||||
if self.selcx.tcx().lazy_normalization() {
|
||||
constant
|
||||
} else {
|
||||
let constant = constant.super_fold_with(self);
|
||||
constant.eval(self.selcx.tcx(), self.param_env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,11 +38,13 @@ use crate::traits::project::ProjectionCacheKeyExt;
|
|||
use rustc_ast::attr;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::ErrorReported;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items;
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::fast_reject;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||
|
@ -503,9 +505,48 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
None,
|
||||
) {
|
||||
Ok(_) => Ok(EvaluatedToOk),
|
||||
Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig),
|
||||
Err(_) => Ok(EvaluatedToErr),
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEquate(c1, c2) => {
|
||||
debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2);
|
||||
|
||||
let evaluate = |c: &'tcx ty::Const<'tcx>| {
|
||||
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
|
||||
self.infcx
|
||||
.const_eval_resolve(
|
||||
obligation.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
promoted,
|
||||
Some(obligation.cause.span),
|
||||
)
|
||||
.map(|val| ty::Const::from_value(self.tcx(), val, c.ty))
|
||||
} else {
|
||||
Ok(c)
|
||||
}
|
||||
};
|
||||
|
||||
match (evaluate(c1), evaluate(c2)) {
|
||||
(Ok(c1), Ok(c2)) => {
|
||||
match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) {
|
||||
Ok(_) => Ok(EvaluatedToOk),
|
||||
Err(_) => Ok(EvaluatedToErr),
|
||||
}
|
||||
}
|
||||
(Err(ErrorHandled::Reported(ErrorReported)), _)
|
||||
| (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr),
|
||||
(Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!(
|
||||
obligation.cause.span(self.tcx()),
|
||||
"ConstEquate: const_eval_resolve returned an unexpected error"
|
||||
),
|
||||
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
|
||||
Ok(EvaluatedToAmbig)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,10 @@ pub fn predicate_obligations<'a, 'tcx>(
|
|||
wf.compute(ty);
|
||||
}
|
||||
}
|
||||
ty::Predicate::ConstEquate(c1, c2) => {
|
||||
wf.compute(c1.ty);
|
||||
wf.compute(c2.ty);
|
||||
}
|
||||
}
|
||||
|
||||
wf.normalize()
|
||||
|
|
|
@ -126,9 +126,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
|
|||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::Subtype(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => {
|
||||
bug!("unexpected predicate {}", predicate)
|
||||
}
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
|
||||
}
|
||||
}
|
||||
ChalkEnvironmentClause::TypeFromEnv(ty) => Some(
|
||||
|
@ -192,9 +191,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
|
|||
Predicate::ObjectSafe(..)
|
||||
| Predicate::ClosureKind(..)
|
||||
| Predicate::Subtype(..)
|
||||
| Predicate::ConstEvaluatable(..) => {
|
||||
chalk_ir::GoalData::All(chalk_ir::Goals::new(interner))
|
||||
}
|
||||
| Predicate::ConstEvaluatable(..)
|
||||
| Predicate::ConstEquate(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -459,7 +457,8 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
|
|||
Predicate::ObjectSafe(..)
|
||||
| Predicate::ClosureKind(..)
|
||||
| Predicate::Subtype(..)
|
||||
| Predicate::ConstEvaluatable(..) => bug!("unexpected predicate {}", &self),
|
||||
| Predicate::ConstEvaluatable(..)
|
||||
| Predicate::ConstEquate(..) => bug!("unexpected predicate {}", &self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,8 @@ fn compute_implied_outlives_bounds<'tcx>(
|
|||
| ty::Predicate::Projection(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => vec![],
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => vec![],
|
||||
|
||||
ty::Predicate::WellFormed(subty) => {
|
||||
wf_types.push(subty);
|
||||
|
|
|
@ -48,6 +48,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool {
|
|||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::Subtype(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => true,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => true,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -793,7 +793,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// `unsafe fn(arg0,arg1,...) -> _`
|
||||
let closure_sig = substs_a.as_closure().sig();
|
||||
let unsafety = fn_ty.unsafety();
|
||||
let pointer_ty = self.tcx.coerce_closure_fn_ty(closure_sig, unsafety);
|
||||
let pointer_ty =
|
||||
self.tcx.mk_fn_ptr(self.tcx.signature_unclosure(closure_sig, unsafety));
|
||||
debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty);
|
||||
self.unify_and(
|
||||
pointer_ty,
|
||||
|
@ -909,23 +910,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
|
||||
|
||||
// Special-case that coercion alone cannot handle:
|
||||
// Two function item types of differing IDs or InternalSubsts.
|
||||
if let (&ty::FnDef(..), &ty::FnDef(..)) = (&prev_ty.kind, &new_ty.kind) {
|
||||
// Don't reify if the function types have a LUB, i.e., they
|
||||
// are the same function and their parameters have a LUB.
|
||||
let lub_ty = self
|
||||
.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
|
||||
.map(|ok| self.register_infer_ok_obligations(ok));
|
||||
|
||||
if lub_ty.is_ok() {
|
||||
// We have a LUB of prev_ty and new_ty, just return it.
|
||||
return lub_ty;
|
||||
// Function items or non-capturing closures of differing IDs or InternalSubsts.
|
||||
let (a_sig, b_sig) = {
|
||||
let is_capturing_closure = |ty| {
|
||||
if let &ty::Closure(_, substs) = ty {
|
||||
substs.as_closure().upvar_tys().next().is_some()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
if is_capturing_closure(&prev_ty.kind) || is_capturing_closure(&new_ty.kind) {
|
||||
(None, None)
|
||||
} else {
|
||||
match (&prev_ty.kind, &new_ty.kind) {
|
||||
(&ty::FnDef(..), &ty::FnDef(..)) => {
|
||||
// Don't reify if the function types have a LUB, i.e., they
|
||||
// are the same function and their parameters have a LUB.
|
||||
match self
|
||||
.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
|
||||
{
|
||||
// We have a LUB of prev_ty and new_ty, just return it.
|
||||
Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)),
|
||||
Err(_) => {
|
||||
(Some(prev_ty.fn_sig(self.tcx)), Some(new_ty.fn_sig(self.tcx)))
|
||||
}
|
||||
}
|
||||
}
|
||||
(&ty::Closure(_, substs), &ty::FnDef(..)) => {
|
||||
let b_sig = new_ty.fn_sig(self.tcx);
|
||||
let a_sig = self
|
||||
.tcx
|
||||
.signature_unclosure(substs.as_closure().sig(), b_sig.unsafety());
|
||||
(Some(a_sig), Some(b_sig))
|
||||
}
|
||||
(&ty::FnDef(..), &ty::Closure(_, substs)) => {
|
||||
let a_sig = prev_ty.fn_sig(self.tcx);
|
||||
let b_sig = self
|
||||
.tcx
|
||||
.signature_unclosure(substs.as_closure().sig(), a_sig.unsafety());
|
||||
(Some(a_sig), Some(b_sig))
|
||||
}
|
||||
(&ty::Closure(_, substs_a), &ty::Closure(_, substs_b)) => (
|
||||
Some(self.tcx.signature_unclosure(
|
||||
substs_a.as_closure().sig(),
|
||||
hir::Unsafety::Normal,
|
||||
)),
|
||||
Some(self.tcx.signature_unclosure(
|
||||
substs_b.as_closure().sig(),
|
||||
hir::Unsafety::Normal,
|
||||
)),
|
||||
),
|
||||
_ => (None, None),
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) {
|
||||
// The signature must match.
|
||||
let a_sig = prev_ty.fn_sig(self.tcx);
|
||||
let a_sig = self.normalize_associated_types_in(new.span, &a_sig);
|
||||
let b_sig = new_ty.fn_sig(self.tcx);
|
||||
let b_sig = self.normalize_associated_types_in(new.span, &b_sig);
|
||||
let sig = self
|
||||
.at(cause, self.param_env)
|
||||
|
@ -935,17 +976,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Reify both sides and return the reified fn pointer type.
|
||||
let fn_ptr = self.tcx.mk_fn_ptr(sig);
|
||||
for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) {
|
||||
// The only adjustment that can produce an fn item is
|
||||
// `NeverToAny`, so this should always be valid.
|
||||
let prev_adjustment = match prev_ty.kind {
|
||||
ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety())),
|
||||
ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let next_adjustment = match new_ty.kind {
|
||||
ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety())),
|
||||
ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
for expr in exprs.iter().map(|e| e.as_coercion_site()) {
|
||||
self.apply_adjustments(
|
||||
expr,
|
||||
vec![Adjustment {
|
||||
kind: Adjust::Pointer(PointerCast::ReifyFnPointer),
|
||||
target: fn_ptr,
|
||||
}],
|
||||
vec![Adjustment { kind: prev_adjustment.clone(), target: fn_ptr }],
|
||||
);
|
||||
}
|
||||
self.apply_adjustments(new, vec![Adjustment { kind: next_adjustment, target: fn_ptr }]);
|
||||
return Ok(fn_ptr);
|
||||
}
|
||||
|
||||
|
|
|
@ -810,7 +810,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::TypeOutlives(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => None,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => None,
|
||||
});
|
||||
|
||||
self.elaborate_bounds(bounds, |this, poly_trait_ref, item| {
|
||||
|
|
|
@ -1648,6 +1648,16 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
|
|||
|
||||
r.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
|
||||
if let ty::ConstKind::Unevaluated(..) = c.val {
|
||||
// FIXME(#72219) We currenctly don't detect lifetimes within substs
|
||||
// which would violate this check. Even though the particular substitution is not used
|
||||
// within the const, this should still be fixed.
|
||||
return false;
|
||||
}
|
||||
c.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
let prohibit_opaque = match item.kind {
|
||||
|
@ -3858,6 +3868,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ty::Predicate::WellFormed(..) => None,
|
||||
ty::Predicate::ObjectSafe(..) => None,
|
||||
ty::Predicate::ConstEvaluatable(..) => None,
|
||||
ty::Predicate::ConstEquate(..) => None,
|
||||
// N.B., this predicate is created by breaking down a
|
||||
// `ClosureType: FnFoo()` predicate, where
|
||||
// `ClosureType` represents some `Closure`. It can't
|
||||
|
|
|
@ -1164,7 +1164,8 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
|||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
Some(tcx.hir().local_def_id(parent_id).to_def_id())
|
||||
}
|
||||
// FIXME(#43408) enable this always when we get lazy normalization.
|
||||
// FIXME(#43408) always enable this once `lazy_normalization` is
|
||||
// stable enough and does not need a feature gate anymore.
|
||||
Node::AnonConst(_) => {
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
let parent_def_id = tcx.hir().local_def_id(parent_id);
|
||||
|
@ -1172,7 +1173,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
|||
// HACK(eddyb) this provides the correct generics when
|
||||
// `feature(const_generics)` is enabled, so that const expressions
|
||||
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
|
||||
if tcx.features().const_generics {
|
||||
if tcx.lazy_normalization() {
|
||||
Some(parent_def_id.to_def_id())
|
||||
} else {
|
||||
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
|
||||
|
|
|
@ -413,6 +413,7 @@ fn trait_predicate_kind<'tcx>(
|
|||
| ty::Predicate::Subtype(_)
|
||||
| ty::Predicate::ObjectSafe(_)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => None,
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
|||
| ty::Predicate::ObjectSafe(..)
|
||||
| ty::Predicate::ClosureKind(..)
|
||||
| ty::Predicate::Subtype(..)
|
||||
| ty::Predicate::ConstEvaluatable(..) => (),
|
||||
| ty::Predicate::ConstEvaluatable(..)
|
||||
| ty::Predicate::ConstEquate(..) => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -493,7 +493,8 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
|
|||
Predicate::WellFormed(..)
|
||||
| Predicate::ObjectSafe(..)
|
||||
| Predicate::ClosureKind(..)
|
||||
| Predicate::ConstEvaluatable(..) => panic!("not user writable"),
|
||||
| Predicate::ConstEvaluatable(..)
|
||||
| Predicate::ConstEquate(..) => panic!("not user writable"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
39
src/test/ui/closures/closure_cap_coerce_many_fail.rs
Normal file
39
src/test/ui/closures/closure_cap_coerce_many_fail.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
fn main() {
|
||||
// We shouldn't coerce capturing closure to a function
|
||||
let cap = 0;
|
||||
let _ = match "+" {
|
||||
"+" => add,
|
||||
"-" => |a, b| (a - b + cap) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
//~^^^ ERROR `match` arms have incompatible types
|
||||
|
||||
|
||||
// We shouldn't coerce capturing closure to a non-capturing closure
|
||||
let _ = match "+" {
|
||||
"+" => |a, b| (a + b) as i32,
|
||||
"-" => |a, b| (a - b + cap) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
//~^^^ ERROR `match` arms have incompatible types
|
||||
|
||||
|
||||
// We shouldn't coerce non-capturing closure to a capturing closure
|
||||
let _ = match "+" {
|
||||
"+" => |a, b| (a + b + cap) as i32,
|
||||
"-" => |a, b| (a - b) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
//~^^^ ERROR `match` arms have incompatible types
|
||||
|
||||
// We shouldn't coerce capturing closure to a capturing closure
|
||||
let _ = match "+" {
|
||||
"+" => |a, b| (a + b + cap) as i32,
|
||||
"-" => |a, b| (a - b + cap) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
//~^^^ ERROR `match` arms have incompatible types
|
||||
}
|
73
src/test/ui/closures/closure_cap_coerce_many_fail.stderr
Normal file
73
src/test/ui/closures/closure_cap_coerce_many_fail.stderr
Normal file
|
@ -0,0 +1,73 @@
|
|||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/closure_cap_coerce_many_fail.rs:9:16
|
||||
|
|
||||
LL | let _ = match "+" {
|
||||
| _____________-
|
||||
LL | | "+" => add,
|
||||
| | --- this is found to be of type `fn(i32, i32) -> i32 {add}`
|
||||
LL | | "-" => |a, b| (a - b + cap) as i32,
|
||||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found closure
|
||||
LL | | _ => unimplemented!(),
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `fn(i32, i32) -> i32 {add}`
|
||||
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43 cap:_]`
|
||||
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/closure_cap_coerce_many_fail.rs:18:16
|
||||
|
|
||||
LL | let _ = match "+" {
|
||||
| _____________-
|
||||
LL | | "+" => |a, b| (a + b) as i32,
|
||||
| | --------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
|
||||
LL | | "-" => |a, b| (a - b + cap) as i32,
|
||||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
|
||||
LL | | _ => unimplemented!(),
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
|
||||
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43 cap:_]`
|
||||
= note: no two closures, even if identical, have the same type
|
||||
= help: consider boxing your closure and/or using it as a trait object
|
||||
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/closure_cap_coerce_many_fail.rs:27:16
|
||||
|
|
||||
LL | let _ = match "+" {
|
||||
| _____________-
|
||||
LL | | "+" => |a, b| (a + b + cap) as i32,
|
||||
| | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]`
|
||||
LL | | "-" => |a, b| (a - b) as i32,
|
||||
| | ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
|
||||
LL | | _ => unimplemented!(),
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]`
|
||||
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]`
|
||||
= note: no two closures, even if identical, have the same type
|
||||
= help: consider boxing your closure and/or using it as a trait object
|
||||
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/closure_cap_coerce_many_fail.rs:35:16
|
||||
|
|
||||
LL | let _ = match "+" {
|
||||
| _____________-
|
||||
LL | | "+" => |a, b| (a + b + cap) as i32,
|
||||
| | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]`
|
||||
LL | | "-" => |a, b| (a - b + cap) as i32,
|
||||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
|
||||
LL | | _ => unimplemented!(),
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]`
|
||||
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43 cap:_]`
|
||||
= note: no two closures, even if identical, have the same type
|
||||
= help: consider boxing your closure and/or using it as a trait object
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
166
src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs
Normal file
166
src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs
Normal file
|
@ -0,0 +1,166 @@
|
|||
// check-pass
|
||||
// Ensure non-capturing Closure passes CoerceMany.
|
||||
fn foo(x: usize) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn bar(x: usize) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// One FnDef and one non-capturing Closure
|
||||
let _ = match 0 {
|
||||
0 => foo,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = match 0 {
|
||||
2 => |a| 2,
|
||||
0 => foo,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = [foo, |a| 2];
|
||||
let _ = [|a| 2, foo];
|
||||
|
||||
|
||||
|
||||
// Two FnDefs and one non-capturing Closure
|
||||
let _ = match 0 {
|
||||
0 => foo,
|
||||
1 => bar,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = match 0 {
|
||||
0 => foo,
|
||||
2 => |a| 2,
|
||||
1 => bar,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = match 0 {
|
||||
2 => |a| 2,
|
||||
0 => foo,
|
||||
1 => bar,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = [foo, bar, |a| 2];
|
||||
let _ = [foo, |a| 2, bar];
|
||||
let _ = [|a| 2, foo, bar];
|
||||
|
||||
|
||||
|
||||
// One FnDef and two non-capturing Closures
|
||||
let _ = match 0 {
|
||||
0 => foo,
|
||||
1 => |a| 1,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = match 0 {
|
||||
1 => |a| 1,
|
||||
0 => foo,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = match 0 {
|
||||
1 => |a| 1,
|
||||
2 => |a| 2,
|
||||
0 => foo,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = [foo, |a| 1, |a| 2];
|
||||
let _ = [|a| 1, foo, |a| 2];
|
||||
let _ = [|a| 1, |a| 2, foo];
|
||||
|
||||
|
||||
|
||||
// Three non-capturing Closures
|
||||
let _ = match 0 {
|
||||
0 => |a: usize| 0,
|
||||
1 => |a| 1,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = [|a: usize| 0, |a| 1, |a| 2];
|
||||
|
||||
|
||||
|
||||
// Three non-capturing Closures variable
|
||||
let clo0 = |a: usize| 0;
|
||||
let clo1 = |a| 1;
|
||||
let clo2 = |a| 2;
|
||||
let _ = match 0 {
|
||||
0 => clo0,
|
||||
1 => clo1,
|
||||
2 => clo2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let clo0 = |a: usize| 0;
|
||||
let clo1 = |a| 1;
|
||||
let clo2 = |a| 2;
|
||||
let _ = [clo0, clo1, clo2];
|
||||
|
||||
|
||||
|
||||
// --- Function pointer related part
|
||||
|
||||
// Closure is not in a variable
|
||||
type FnPointer = fn(usize) -> usize;
|
||||
|
||||
let _ = match 0 {
|
||||
0 => foo as FnPointer,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let _ = match 0 {
|
||||
2 => |a| 2,
|
||||
0 => foo as FnPointer,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let _ = [foo as FnPointer, |a| 2];
|
||||
let _ = [|a| 2, foo as FnPointer];
|
||||
let _ = [foo, bar, |x| x];
|
||||
let _ = [foo as FnPointer, bar, |x| x];
|
||||
let _ = [foo, bar as FnPointer, |x| x];
|
||||
let _ = [foo, bar, (|x| x) as FnPointer];
|
||||
let _ = [foo as FnPointer, bar as FnPointer, |x| x];
|
||||
|
||||
// Closure is in a variable
|
||||
let x = |a| 2;
|
||||
let _ = match 0 {
|
||||
0 => foo as FnPointer,
|
||||
2 => x,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let x = |a| 2;
|
||||
let _ = match 0 {
|
||||
2 => x,
|
||||
0 => foo as FnPointer,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let x = |a| 2;
|
||||
let _ = [foo as FnPointer, x];
|
||||
let _ = [x, foo as FnPointer];
|
||||
|
||||
let x = |a| 2;
|
||||
let _ = [foo, bar, x];
|
||||
let x: FnPointer = |a| 2;
|
||||
let _ = [foo, bar, x];
|
||||
let x = |a| 2;
|
||||
let _ = [foo, bar as FnPointer, x];
|
||||
let x = |a| 2;
|
||||
let _ = [foo as FnPointer, bar, x];
|
||||
let x = |a| 2;
|
||||
let _ = [foo as FnPointer, bar as FnPointer, x];
|
||||
}
|
59
src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs
Normal file
59
src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
// run-pass
|
||||
// Ensure non-capturing Closure passing CoerceMany work correctly.
|
||||
fn foo(_: usize) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn bar(_: usize) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Coerce result check
|
||||
|
||||
type FnPointer = fn(usize) -> usize;
|
||||
|
||||
let c = |x| x;
|
||||
let c_pointer: FnPointer = c;
|
||||
assert_eq!(c_pointer(42), 42);
|
||||
|
||||
let f = match 0 {
|
||||
0 => foo,
|
||||
1 => |_| 1,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(f(42), 0);
|
||||
|
||||
let f = match 2 {
|
||||
2 => |_| 2,
|
||||
0 => foo,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(f(42), 2);
|
||||
|
||||
let f = match 1 {
|
||||
0 => foo,
|
||||
1 => bar,
|
||||
2 => |_| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(f(42), 1);
|
||||
|
||||
let clo0 = |_: usize| 0;
|
||||
let clo1 = |_| 1;
|
||||
let clo2 = |_| 2;
|
||||
let f = match 0 {
|
||||
0 => clo0,
|
||||
1 => clo1,
|
||||
2 => clo2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(f(42), 0);
|
||||
|
||||
let funcs = [add, |a, b| (a - b) as i32];
|
||||
assert_eq!([funcs[0](5, 5), funcs[1](5, 5)], [10, 0]);
|
||||
}
|
22
src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs
Normal file
22
src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Ensure we get unsafe function after coercion
|
||||
unsafe fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
fn main() {
|
||||
// We can coerce non-capturing closure to unsafe function
|
||||
let foo = match "+" {
|
||||
"+" => add,
|
||||
"-" => |a, b| (a - b) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let result: i32 = foo(5, 5); //~ ERROR call to unsafe function
|
||||
|
||||
|
||||
// We can coerce unsafe function to non-capturing closure
|
||||
let foo = match "+" {
|
||||
"-" => |a, b| (a - b) as i32,
|
||||
"+" => add,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let result: i32 = foo(5, 5); //~ ERROR call to unsafe function
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
||||
--> $DIR/closure_no_cap_coerce_many_unsafe_0.rs:12:23
|
||||
|
|
||||
LL | let result: i32 = foo(5, 5);
|
||||
| ^^^^^^^^^ call to unsafe function
|
||||
|
|
||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
||||
--> $DIR/closure_no_cap_coerce_many_unsafe_0.rs:21:23
|
||||
|
|
||||
LL | let result: i32 = foo(5, 5);
|
||||
| ^^^^^^^^^ call to unsafe function
|
||||
|
|
||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0133`.
|
23
src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs
Normal file
23
src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// run-pass
|
||||
// Ensure we get correct unsafe function after coercion
|
||||
unsafe fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
fn main() {
|
||||
// We can coerce non-capturing closure to unsafe function
|
||||
let foo = match "+" {
|
||||
"+" => add,
|
||||
"-" => |a, b| (a - b) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(unsafe { foo(5, 5) }, 10);
|
||||
|
||||
|
||||
// We can coerce unsafe function to non-capturing closure
|
||||
let foo = match "-" {
|
||||
"-" => |a, b| (a - b) as i32,
|
||||
"+" => add,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(unsafe { foo(5, 5) }, 0);
|
||||
}
|
9
src/test/ui/closures/issue-46742.rs
Normal file
9
src/test/ui/closures/issue-46742.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// check-pass
|
||||
fn main() {
|
||||
let _: i32 = (match "" {
|
||||
"+" => ::std::ops::Add::add,
|
||||
"-" => ::std::ops::Sub::sub,
|
||||
"<" => |a,b| (a < b) as i32,
|
||||
_ => unimplemented!(),
|
||||
})(5, 5);
|
||||
}
|
14
src/test/ui/closures/issue-48109.rs
Normal file
14
src/test/ui/closures/issue-48109.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// check-pass
|
||||
fn useful(i: usize) -> usize {
|
||||
i
|
||||
}
|
||||
|
||||
fn useful2(i: usize) -> usize {
|
||||
i
|
||||
}
|
||||
|
||||
fn main() {
|
||||
for f in &[useful, useful2, |x| x] {
|
||||
println!("{}", f(6));
|
||||
}
|
||||
}
|
|
@ -13,8 +13,8 @@ error[E0308]: mismatched types
|
|||
LL | x = Const::<{ [4] }> {};
|
||||
| ^^^^^^^^^^^^^^^^^^^ expected `3usize`, found `4usize`
|
||||
|
|
||||
= note: expected struct `Const<[3usize]>`
|
||||
found struct `Const<[4usize]>`
|
||||
= note: expected type `[3usize]`
|
||||
found type `[4usize]`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
|
|
|
@ -11,12 +11,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/fn-const-param-infer.rs:16:31
|
||||
|
|
||||
LL | let _: Checked<not_one> = Checked::<not_two>;
|
||||
| ---------------- ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}`
|
||||
| |
|
||||
| expected due to this
|
||||
| ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}`
|
||||
|
|
||||
= note: expected struct `Checked<{not_one as fn(usize) -> bool}>`
|
||||
found struct `Checked<{not_two as fn(usize) -> bool}>`
|
||||
= note: expected type `{not_one as fn(usize) -> bool}`
|
||||
found type `{not_two as fn(usize) -> bool}`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/fn-const-param-infer.rs:20:24
|
||||
|
@ -37,12 +35,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/fn-const-param-infer.rs:25:40
|
||||
|
|
||||
LL | let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
|
||||
| ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic::<u32> as fn(usize) -> bool}`, found `{generic::<u16> as fn(usize) -> bool}`
|
||||
| |
|
||||
| expected due to this
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic::<u32> as fn(usize) -> bool}`, found `{generic::<u16> as fn(usize) -> bool}`
|
||||
|
|
||||
= note: expected struct `Checked<{generic::<u32> as fn(usize) -> bool}>`
|
||||
found struct `Checked<{generic::<u16> as fn(usize) -> bool}>`
|
||||
= note: expected type `{generic::<u32> as fn(usize) -> bool}`
|
||||
found type `{generic::<u16> as fn(usize) -> bool}`
|
||||
|
||||
error: aborting due to 4 previous errors; 1 warning emitted
|
||||
|
||||
|
|
24
src/test/ui/const-generics/issues/issue-61935.rs
Normal file
24
src/test/ui/const-generics/issues/issue-61935.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete
|
||||
|
||||
trait Foo {}
|
||||
|
||||
impl<const N: usize> Foo for [(); N]
|
||||
where
|
||||
Self:FooImpl<{N==0}>
|
||||
{}
|
||||
|
||||
trait FooImpl<const IS_ZERO: bool>{}
|
||||
|
||||
impl FooImpl<true> for [(); 0] {}
|
||||
|
||||
impl<const N:usize> FooImpl<false> for [();N] {}
|
||||
|
||||
fn foo(_: impl Foo) {}
|
||||
|
||||
fn main() {
|
||||
foo([]);
|
||||
foo([()]);
|
||||
}
|
11
src/test/ui/const-generics/issues/issue-61935.stderr
Normal file
11
src/test/ui/const-generics/issues/issue-61935.stderr
Normal file
|
@ -0,0 +1,11 @@
|
|||
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/issue-61935.rs:3:12
|
||||
|
|
||||
LL | #![feature(const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
|
@ -16,8 +16,7 @@ struct ArrayHolder<const X: usize>([u32; X]);
|
|||
impl<const X: usize> ArrayHolder<X> {
|
||||
pub const fn new() -> Self {
|
||||
ArrayHolder([0; Self::SIZE])
|
||||
//~^ ERROR: mismatched types
|
||||
//~| ERROR constant expression depends on a generic parameter
|
||||
//~^ ERROR constant expression depends on a generic parameter
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-62504.rs:18:21
|
||||
|
|
||||
LL | ArrayHolder([0; Self::SIZE])
|
||||
| ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
|
||||
|
|
||||
= note: expected array `[u32; X]`
|
||||
found array `[u32; _]`
|
||||
|
||||
error: constant expression depends on a generic parameter
|
||||
--> $DIR/issue-62504.rs:18:25
|
||||
|
|
||||
|
@ -15,6 +6,5 @@ LL | ArrayHolder([0; Self::SIZE])
|
|||
|
|
||||
= note: this may fail depending on what value the parameter takes
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#![allow(incomplete_features, dead_code, unconditional_recursion)]
|
||||
#![feature(const_generics)]
|
||||
#![feature(lazy_normalization_consts)]
|
||||
|
||||
fn fact<const N: usize>() {
|
||||
fact::<{ N - 1 }>();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: constant expression depends on a generic parameter
|
||||
--> $DIR/issue-66205.rs:5:12
|
||||
--> $DIR/issue-66205.rs:6:12
|
||||
|
|
||||
LL | fact::<{ N - 1 }>();
|
||||
| ^^^^^^^^^
|
||||
|
|
32
src/test/ui/const-generics/issues/issue-67185-1.rs
Normal file
32
src/test/ui/const-generics/issues/issue-67185-1.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
// check-pass
|
||||
|
||||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete
|
||||
|
||||
trait Baz {
|
||||
type Quaks;
|
||||
}
|
||||
impl Baz for u8 {
|
||||
type Quaks = [u16; 3];
|
||||
}
|
||||
|
||||
trait Bar {}
|
||||
impl Bar for [u16; 3] {}
|
||||
impl Bar for [[u16; 3]; 2] {}
|
||||
|
||||
trait Foo
|
||||
where
|
||||
[<u8 as Baz>::Quaks; 2]: Bar,
|
||||
<u8 as Baz>::Quaks: Bar,
|
||||
{
|
||||
}
|
||||
|
||||
struct FooImpl;
|
||||
|
||||
impl Foo for FooImpl {}
|
||||
|
||||
fn f(_: impl Foo) {}
|
||||
|
||||
fn main() {
|
||||
f(FooImpl)
|
||||
}
|
11
src/test/ui/const-generics/issues/issue-67185-1.stderr
Normal file
11
src/test/ui/const-generics/issues/issue-67185-1.stderr
Normal file
|
@ -0,0 +1,11 @@
|
|||
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/issue-67185-1.rs:3:12
|
||||
|
|
||||
LL | #![feature(const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
35
src/test/ui/const-generics/issues/issue-67185-2.rs
Normal file
35
src/test/ui/const-generics/issues/issue-67185-2.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete
|
||||
|
||||
trait Baz {
|
||||
type Quaks;
|
||||
}
|
||||
impl Baz for u8 {
|
||||
type Quaks = [u16; 3];
|
||||
}
|
||||
|
||||
trait Bar {}
|
||||
impl Bar for [u16; 4] {}
|
||||
impl Bar for [[u16; 3]; 3] {}
|
||||
|
||||
trait Foo //~ ERROR the trait bound `[u16; 3]: Bar` is not satisfied [E0277]
|
||||
//~^ ERROR the trait bound `[[u16; 3]; 2]: Bar` is not satisfied [E0277]
|
||||
where
|
||||
[<u8 as Baz>::Quaks; 2]: Bar,
|
||||
<u8 as Baz>::Quaks: Bar,
|
||||
{
|
||||
}
|
||||
|
||||
struct FooImpl;
|
||||
|
||||
impl Foo for FooImpl {}
|
||||
//~^ ERROR the trait bound `[u16; 3]: Bar` is not satisfied [E0277]
|
||||
//~^^ ERROR the trait bound `[[u16; 3]; 2]: Bar` is not satisfied [E0277]
|
||||
|
||||
fn f(_: impl Foo) {}
|
||||
//~^ ERROR the trait bound `[u16; 3]: Bar` is not satisfied [E0277]
|
||||
//~^^ ERROR the trait bound `[[u16; 3]; 2]: Bar` is not satisfied [E0277]
|
||||
|
||||
fn main() {
|
||||
f(FooImpl)
|
||||
}
|
112
src/test/ui/const-generics/issues/issue-67185-2.stderr
Normal file
112
src/test/ui/const-generics/issues/issue-67185-2.stderr
Normal file
|
@ -0,0 +1,112 @@
|
|||
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/issue-67185-2.rs:1:12
|
||||
|
|
||||
LL | #![feature(const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
|
||||
|
||||
error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
|
||||
--> $DIR/issue-67185-2.rs:15:1
|
||||
|
|
||||
LL | / trait Foo
|
||||
LL | |
|
||||
LL | | where
|
||||
LL | | [<u8 as Baz>::Quaks; 2]: Bar,
|
||||
LL | | <u8 as Baz>::Quaks: Bar,
|
||||
LL | | {
|
||||
LL | | }
|
||||
| |_^ the trait `Bar` is not implemented for `[u16; 3]`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<[[u16; 3]; 3] as Bar>
|
||||
<[u16; 4] as Bar>
|
||||
= help: see issue #48214
|
||||
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
|
||||
|
||||
error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
|
||||
--> $DIR/issue-67185-2.rs:15:1
|
||||
|
|
||||
LL | / trait Foo
|
||||
LL | |
|
||||
LL | | where
|
||||
LL | | [<u8 as Baz>::Quaks; 2]: Bar,
|
||||
LL | | <u8 as Baz>::Quaks: Bar,
|
||||
LL | | {
|
||||
LL | | }
|
||||
| |_^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<[[u16; 3]; 3] as Bar>
|
||||
<[u16; 4] as Bar>
|
||||
= help: see issue #48214
|
||||
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
|
||||
|
||||
error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
|
||||
--> $DIR/issue-67185-2.rs:25:6
|
||||
|
|
||||
LL | trait Foo
|
||||
| --- required by a bound in this
|
||||
...
|
||||
LL | <u8 as Baz>::Quaks: Bar,
|
||||
| --- required by this bound in `Foo`
|
||||
...
|
||||
LL | impl Foo for FooImpl {}
|
||||
| ^^^ the trait `Bar` is not implemented for `[u16; 3]`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<[[u16; 3]; 3] as Bar>
|
||||
<[u16; 4] as Bar>
|
||||
|
||||
error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
|
||||
--> $DIR/issue-67185-2.rs:25:6
|
||||
|
|
||||
LL | trait Foo
|
||||
| --- required by a bound in this
|
||||
...
|
||||
LL | [<u8 as Baz>::Quaks; 2]: Bar,
|
||||
| --- required by this bound in `Foo`
|
||||
...
|
||||
LL | impl Foo for FooImpl {}
|
||||
| ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<[[u16; 3]; 3] as Bar>
|
||||
<[u16; 4] as Bar>
|
||||
|
||||
error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
|
||||
--> $DIR/issue-67185-2.rs:29:14
|
||||
|
|
||||
LL | trait Foo
|
||||
| --- required by a bound in this
|
||||
...
|
||||
LL | [<u8 as Baz>::Quaks; 2]: Bar,
|
||||
| --- required by this bound in `Foo`
|
||||
...
|
||||
LL | fn f(_: impl Foo) {}
|
||||
| ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<[[u16; 3]; 3] as Bar>
|
||||
<[u16; 4] as Bar>
|
||||
|
||||
error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
|
||||
--> $DIR/issue-67185-2.rs:29:14
|
||||
|
|
||||
LL | trait Foo
|
||||
| --- required by a bound in this
|
||||
...
|
||||
LL | <u8 as Baz>::Quaks: Bar,
|
||||
| --- required by this bound in `Foo`
|
||||
...
|
||||
LL | fn f(_: impl Foo) {}
|
||||
| ^^^ the trait `Bar` is not implemented for `[u16; 3]`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<[[u16; 3]; 3] as Bar>
|
||||
<[u16; 4] as Bar>
|
||||
|
||||
error: aborting due to 6 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
|
@ -1,18 +0,0 @@
|
|||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Bar<O> {}
|
||||
impl<O> Bar<O> for [u8; O] {}
|
||||
//~^ ERROR expected value, found type parameter `O`
|
||||
|
||||
struct Foo<const O: usize> {}
|
||||
impl<const O: usize> Foo<O>
|
||||
where
|
||||
[u8; O]: Bar<[(); O]>,
|
||||
{
|
||||
fn foo() {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Foo::foo();
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
error[E0423]: expected value, found type parameter `O`
|
||||
--> $DIR/issue-69654.rs:5:25
|
||||
|
|
||||
LL | impl<O> Bar<O> for [u8; O] {}
|
||||
| ^ help: a tuple variant with a similar name exists: `Ok`
|
||||
|
|
||||
::: $SRC_DIR/libcore/result.rs:LL:COL
|
||||
|
|
||||
LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
|
||||
| --------------------------------------------------- similarly named tuple variant `Ok` defined here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0423`.
|
19
src/test/ui/const-generics/lazy-normalization/issue-71922.rs
Normal file
19
src/test/ui/const-generics/lazy-normalization/issue-71922.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// run-pass
|
||||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
trait Foo {}
|
||||
|
||||
impl<const N: usize> Foo for [(); N] where Self: FooImpl<{ N == 0 }> {}
|
||||
|
||||
trait FooImpl<const IS_ZERO: bool> {}
|
||||
|
||||
impl FooImpl<{ 0u8 == 0u8 }> for [(); 0] {}
|
||||
|
||||
impl<const N: usize> FooImpl<{ 0u8 != 0u8 }> for [(); N] {}
|
||||
|
||||
fn foo<T: Foo>(_: T) {}
|
||||
|
||||
fn main() {
|
||||
foo([]);
|
||||
foo([()]);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// check-pass
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(const_generics)]
|
||||
|
||||
pub trait Foo<const B: bool> {}
|
||||
pub fn bar<T: Foo<{ true }>>() {}
|
||||
|
||||
fn main() {}
|
|
@ -11,12 +11,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/raw-ptr-const-param.rs:7:40
|
||||
|
|
||||
LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
|
||||
| ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
|
||||
| |
|
||||
| expected due to this
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
|
||||
|
|
||||
= note: expected struct `Const<{0xf as *const u32}>`
|
||||
found struct `Const<{0xa as *const u32}>`
|
||||
= note: expected type `{0xf as *const u32}`
|
||||
found type `{0xa as *const u32}`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
|
|
|
@ -11,12 +11,10 @@ error[E0308]: mismatched types
|
|||
--> $DIR/types-mismatch-const-args.rs:13:41
|
||||
|
|
||||
LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData };
|
||||
| -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2u32`, found `4u32`
|
||||
| |
|
||||
| expected due to this
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2u32`, found `4u32`
|
||||
|
|
||||
= note: expected struct `A<'_, _, 2u32, _>`
|
||||
found struct `A<'_, _, 4u32, _>`
|
||||
= note: expected type `2u32`
|
||||
found type `4u32`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/types-mismatch-const-args.rs:15:41
|
||||
|
@ -26,8 +24,8 @@ LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data
|
|||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected struct `A<'a, u16, _, _>`
|
||||
found struct `A<'b, u32, _, _>`
|
||||
= note: expected struct `A<'a, u16, {2u32}, {3u32}>`
|
||||
found struct `A<'b, u32, {2u32}, {3u32}>`
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ fn closure_from_match() {
|
|||
2 => |c| c - 1,
|
||||
_ => |c| c - 1
|
||||
};
|
||||
//~^^^ ERROR `match` arms have incompatible types
|
||||
//~^^^^ ERROR type annotations needed
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -11,24 +11,13 @@ LL | x = |c| c + 1;
|
|||
= note: no two closures, even if identical, have the same type
|
||||
= help: consider boxing your closure and/or using it as a trait object
|
||||
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/issue-24036.rs:10:14
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/issue-24036.rs:9:15
|
||||
|
|
||||
LL | let x = match 1usize {
|
||||
| _____________-
|
||||
LL | | 1 => |c| c + 1,
|
||||
| | --------- this is found to be of type `[closure@$DIR/issue-24036.rs:9:14: 9:23]`
|
||||
LL | | 2 => |c| c - 1,
|
||||
| | ^^^^^^^^^ expected closure, found a different closure
|
||||
LL | | _ => |c| c - 1
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `[closure@$DIR/issue-24036.rs:9:14: 9:23]`
|
||||
found closure `[closure@$DIR/issue-24036.rs:10:14: 10:23]`
|
||||
= note: no two closures, even if identical, have the same type
|
||||
= help: consider boxing your closure and/or using it as a trait object
|
||||
LL | 1 => |c| c + 1,
|
||||
| ^ consider giving this closure parameter a type
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
Some errors have detailed explanations: E0282, E0308.
|
||||
For more information about an error, try `rustc --explain E0282`.
|
||||
|
|
|
@ -25,7 +25,7 @@ error: non-defining opaque type use in defining scope
|
|||
LL | fn concrete_const() -> OneConst<{123}> {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: used non-generic constant `123usize` for generic parameter
|
||||
note: used non-generic constant `{123}` for generic parameter
|
||||
--> $DIR/generic_nondefining_use.rs:10:21
|
||||
|
|
||||
LL | type OneConst<const X: usize> = impl Debug;
|
||||
|
|
|
@ -18,6 +18,7 @@ use std::thread;
|
|||
use std::time::Duration;
|
||||
|
||||
const REMOTE_ADDR_ENV: &str = "TEST_DEVICE_ADDR";
|
||||
const DEFAULT_ADDR: &str = "127.0.0.1:12345";
|
||||
|
||||
macro_rules! t {
|
||||
($e:expr) => {
|
||||
|
@ -30,8 +31,12 @@ macro_rules! t {
|
|||
|
||||
fn main() {
|
||||
let mut args = env::args().skip(1);
|
||||
let next = args.next();
|
||||
if next.is_none() {
|
||||
return help();
|
||||
}
|
||||
|
||||
match &args.next().unwrap()[..] {
|
||||
match &next.unwrap()[..] {
|
||||
"spawn-emulator" => spawn_emulator(
|
||||
&args.next().unwrap(),
|
||||
Path::new(&args.next().unwrap()),
|
||||
|
@ -40,12 +45,16 @@ fn main() {
|
|||
),
|
||||
"push" => push(Path::new(&args.next().unwrap())),
|
||||
"run" => run(args.next().unwrap(), args.collect()),
|
||||
cmd => panic!("unknown command: {}", cmd),
|
||||
"help" | "-h" | "--help" => help(),
|
||||
cmd => {
|
||||
println!("unknown command: {}", cmd);
|
||||
help();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_emulator(target: &str, server: &Path, tmpdir: &Path, rootfs: Option<PathBuf>) {
|
||||
let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or("127.0.0.1:12345".to_string());
|
||||
let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or(DEFAULT_ADDR.to_string());
|
||||
|
||||
if env::var(REMOTE_ADDR_ENV).is_ok() {
|
||||
println!("Connecting to remote device {} ...", device_address);
|
||||
|
@ -172,7 +181,7 @@ fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path
|
|||
}
|
||||
|
||||
fn push(path: &Path) {
|
||||
let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or("127.0.0.1:12345".to_string());
|
||||
let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or(DEFAULT_ADDR.to_string());
|
||||
let client = t!(TcpStream::connect(device_address));
|
||||
let mut client = BufWriter::new(client);
|
||||
t!(client.write_all(b"push"));
|
||||
|
@ -189,7 +198,7 @@ fn push(path: &Path) {
|
|||
}
|
||||
|
||||
fn run(files: String, args: Vec<String>) {
|
||||
let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or("127.0.0.1:12345".to_string());
|
||||
let device_address = env::var(REMOTE_ADDR_ENV).unwrap_or(DEFAULT_ADDR.to_string());
|
||||
let client = t!(TcpStream::connect(device_address));
|
||||
let mut client = BufWriter::new(client);
|
||||
t!(client.write_all(b"run "));
|
||||
|
@ -284,3 +293,40 @@ fn send(path: &Path, dst: &mut dyn Write) {
|
|||
t!(dst.write_all(&[(amt >> 24) as u8, (amt >> 16) as u8, (amt >> 8) as u8, (amt >> 0) as u8,]));
|
||||
t!(io::copy(&mut file, dst));
|
||||
}
|
||||
|
||||
fn help() {
|
||||
println!(
|
||||
"
|
||||
Usage: {0} <command> [<args>]
|
||||
|
||||
Sub-commands:
|
||||
spawn-emulator <target> <server> <tmpdir> [rootfs] See below
|
||||
push <path> Copy <path> to emulator
|
||||
run <files> [args...] Run program on emulator
|
||||
help Display help message
|
||||
|
||||
Spawning an emulator:
|
||||
|
||||
For Android <target>s, adb will push the <server>, set up TCP forwarding and run
|
||||
the <server>. Otherwise qemu emulates the target using a rootfs image created in
|
||||
<tmpdir> and generated from <rootfs> plus the <server> executable.
|
||||
If {1} is set in the environment, this step is skipped.
|
||||
|
||||
Pushing a path to a running emulator:
|
||||
|
||||
A running emulator or adb device is connected to at the IP address and port in
|
||||
the {1} environment variable or {2} if this isn't
|
||||
specified. The file at <path> is sent to this target.
|
||||
|
||||
Executing commands on a running emulator:
|
||||
|
||||
First the target emulator/adb session is connected to as for pushing files. Next
|
||||
the colon separated list of <files> is pushed to the target. Finally, the first
|
||||
file in <files> is executed in the emulator, preserving the current environment.
|
||||
That command's status code is returned.
|
||||
",
|
||||
env::args().next().unwrap(),
|
||||
REMOTE_ADDR_ENV,
|
||||
DEFAULT_ADDR
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue