mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #118107 - matthiaskrgr:rollup-k5bfkfr, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #117327 (Add documentation for some queries) - #117835 (Note about object lifetime defaults in does not live long enough error) - #117851 (Uplift `InferConst` to `rustc_type_ir`) - #117973 (test: Add test for async-move in 2015 Rust proc macro) - #117992 (Don't require intercrate mode for negative coherence) - #118010 (Typeck break expr even if break is illegal) - #118026 (Don't consider regions in `deref_into_dyn_supertrait` lint) - #118089 (intercrate_ambiguity_causes: handle self ty infer + reservation impls) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
baf4abff31
@ -5,12 +5,13 @@ use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
|
||||
use rustc_middle::mir::{
|
||||
Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location,
|
||||
Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::{self, RegionVid, TyCtxt};
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::{sym, DesugaringKind, Span};
|
||||
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
|
||||
@ -290,12 +291,69 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
if let ConstraintCategory::Cast { unsize_to: Some(unsize_ty) } = category {
|
||||
self.add_object_lifetime_default_note(tcx, err, unsize_ty);
|
||||
}
|
||||
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_object_lifetime_default_note(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
unsize_ty: Ty<'tcx>,
|
||||
) {
|
||||
if let ty::Adt(def, args) = unsize_ty.kind() {
|
||||
// We try to elaborate the object lifetime defaults and present those to the user. This should
|
||||
// make it clear where the region constraint is coming from.
|
||||
let generics = tcx.generics_of(def.did());
|
||||
|
||||
let mut has_dyn = false;
|
||||
let mut failed = false;
|
||||
|
||||
let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
|
||||
if let Some(ty::Dynamic(obj, _, ty::DynKind::Dyn)) = arg.as_type().map(Ty::kind) {
|
||||
let default = tcx.object_lifetime_default(param.def_id);
|
||||
|
||||
let re_static = tcx.lifetimes.re_static;
|
||||
|
||||
let implied_region = match default {
|
||||
// This is not entirely precise.
|
||||
ObjectLifetimeDefault::Empty => re_static,
|
||||
ObjectLifetimeDefault::Ambiguous => {
|
||||
failed = true;
|
||||
re_static
|
||||
}
|
||||
ObjectLifetimeDefault::Param(param_def_id) => {
|
||||
let index = generics.param_def_id_to_index[¶m_def_id] as usize;
|
||||
args.get(index).and_then(|arg| arg.as_region()).unwrap_or_else(|| {
|
||||
failed = true;
|
||||
re_static
|
||||
})
|
||||
}
|
||||
ObjectLifetimeDefault::Static => re_static,
|
||||
};
|
||||
|
||||
has_dyn = true;
|
||||
|
||||
Ty::new_dynamic(tcx, obj, implied_region, ty::DynKind::Dyn).into()
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
});
|
||||
let elaborated_ty = Ty::new_adt(tcx, *def, tcx.mk_args_from_iter(elaborated_args));
|
||||
|
||||
if has_dyn && !failed {
|
||||
err.note(format!(
|
||||
"due to object lifetime defaults, `{unsize_ty}` actually means `{elaborated_ty}`"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_lifetime_bound_suggestion_to_diagnostic(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
|
@ -53,7 +53,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
|
||||
ConstraintCategory::Yield => "yielding this value ",
|
||||
ConstraintCategory::UseAsConst => "using this value as a constant ",
|
||||
ConstraintCategory::UseAsStatic => "using this value as a static ",
|
||||
ConstraintCategory::Cast => "cast ",
|
||||
ConstraintCategory::Cast { .. } => "cast ",
|
||||
ConstraintCategory::CallArgument(_) => "argument ",
|
||||
ConstraintCategory::TypeAnnotation => "type annotation ",
|
||||
ConstraintCategory::ClosureBounds => "closure body ",
|
||||
|
@ -1934,7 +1934,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
*ty,
|
||||
ty_fn_ptr_from,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
@ -1959,7 +1959,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
*ty,
|
||||
ty_fn_ptr_from,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
@ -1988,7 +1988,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
*ty,
|
||||
ty_fn_ptr_from,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
@ -2013,7 +2013,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.prove_trait_ref(
|
||||
trait_ref,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast {
|
||||
unsize_to: Some(tcx.fold_regions(ty, |r, _| {
|
||||
if let ty::ReVar(_) = r.kind() {
|
||||
tcx.lifetimes.re_erased
|
||||
} else {
|
||||
r
|
||||
}
|
||||
})),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -2033,7 +2041,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
.iter()
|
||||
.map(|predicate| predicate.with_self_ty(tcx, self_ty)),
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
);
|
||||
|
||||
let outlives_predicate = tcx.mk_predicate(Binder::dummy(
|
||||
@ -2044,7 +2052,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
self.prove_predicate(
|
||||
outlives_predicate,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
);
|
||||
}
|
||||
|
||||
@ -2065,7 +2073,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
*ty_from,
|
||||
*ty_to,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
@ -2131,7 +2139,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
*ty_elem,
|
||||
*ty_to,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
|
@ -626,15 +626,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
let coerce_to = match opt_coerce_to {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
// If the loop context is not a `loop { }`, then break with
|
||||
// a value is illegal, and `opt_coerce_to` will be `None`.
|
||||
// Return error in that case (#114529).
|
||||
return Ty::new_misc_error(tcx);
|
||||
}
|
||||
};
|
||||
// If the loop context is not a `loop { }`, then break with
|
||||
// a value is illegal, and `opt_coerce_to` will be `None`.
|
||||
// Set expectation to error in that case and set tainted
|
||||
// by error (#114529)
|
||||
let coerce_to = opt_coerce_to.unwrap_or_else(|| {
|
||||
let guar = tcx.sess.delay_span_bug(
|
||||
expr.span,
|
||||
"illegal break with value found but no error reported",
|
||||
);
|
||||
self.set_tainted_by_errors(guar);
|
||||
Ty::new_error(tcx, guar)
|
||||
});
|
||||
|
||||
// Recurse without `enclosing_breakables` borrowed.
|
||||
e_ty = self.check_expr_with_hint(e, coerce_to);
|
||||
|
@ -65,8 +65,15 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
|
||||
/// Forks the inference context, creating a new inference context with the same inference
|
||||
/// variables in the same state. This can be used to "branch off" many tests from the same
|
||||
/// common state. Used in coherence.
|
||||
/// common state.
|
||||
pub fn fork(&self) -> Self {
|
||||
self.fork_with_intercrate(self.intercrate)
|
||||
}
|
||||
|
||||
/// Forks the inference context, creating a new inference context with the same inference
|
||||
/// variables in the same state, except possibly changing the intercrate mode. This can be
|
||||
/// used to "branch off" many tests from the same common state. Used in negative coherence.
|
||||
pub fn fork_with_intercrate(&self, intercrate: bool) -> Self {
|
||||
Self {
|
||||
tcx: self.tcx,
|
||||
defining_use_anchor: self.defining_use_anchor,
|
||||
@ -81,7 +88,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
tainted_by_errors: self.tainted_by_errors.clone(),
|
||||
err_count_on_creation: self.err_count_on_creation,
|
||||
universe: self.universe.clone(),
|
||||
intercrate: self.intercrate,
|
||||
intercrate,
|
||||
next_trait_solver: self.next_trait_solver,
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ declare_lint! {
|
||||
Warn,
|
||||
"`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
|
||||
reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
|
||||
reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
|
||||
};
|
||||
}
|
||||
@ -59,12 +59,13 @@ declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
let tcx = cx.tcx;
|
||||
// `Deref` is being implemented for `t`
|
||||
if let hir::ItemKind::Impl(impl_) = item.kind
|
||||
&& let Some(trait_) = &impl_.of_trait
|
||||
&& let t = cx.tcx.type_of(item.owner_id).instantiate_identity()
|
||||
&& let t = tcx.type_of(item.owner_id).instantiate_identity()
|
||||
&& let opt_did @ Some(did) = trait_.trait_def_id()
|
||||
&& opt_did == cx.tcx.lang_items().deref_trait()
|
||||
&& opt_did == tcx.lang_items().deref_trait()
|
||||
// `t` is `dyn t_principal`
|
||||
&& let ty::Dynamic(data, _, ty::Dyn) = t.kind()
|
||||
&& let Some(t_principal) = data.principal()
|
||||
@ -73,9 +74,14 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
|
||||
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
|
||||
&& let Some(target_principal) = data.principal()
|
||||
// `target_principal` is a supertrait of `t_principal`
|
||||
&& supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self))
|
||||
.any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal)
|
||||
&& supertraits(tcx, t_principal.with_self_ty(tcx, tcx.types.trait_object_dummy_self))
|
||||
.any(|sup| {
|
||||
tcx.erase_regions(
|
||||
sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(tcx, x)),
|
||||
) == tcx.erase_regions(target_principal)
|
||||
})
|
||||
{
|
||||
let t = tcx.erase_regions(t);
|
||||
let label = impl_
|
||||
.items
|
||||
.iter()
|
||||
@ -83,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
|
||||
.map(|label| SupertraitAsDerefTargetLabel { label });
|
||||
cx.emit_spanned_lint(
|
||||
DEREF_INTO_DYN_SUPERTRAIT,
|
||||
cx.tcx.def_span(item.owner_id.def_id),
|
||||
tcx.def_span(item.owner_id.def_id),
|
||||
SupertraitAsDerefTarget { t, target_principal, label },
|
||||
);
|
||||
}
|
||||
|
@ -341,7 +341,11 @@ pub enum ConstraintCategory<'tcx> {
|
||||
UseAsConst,
|
||||
UseAsStatic,
|
||||
TypeAnnotation,
|
||||
Cast,
|
||||
Cast {
|
||||
/// Whether this is an unsizing cast and if yes, this contains the target type.
|
||||
/// Region variables are erased to ReErased.
|
||||
unsize_to: Option<Ty<'tcx>>,
|
||||
},
|
||||
|
||||
/// A constraint that came from checking the body of a closure.
|
||||
///
|
||||
|
@ -109,10 +109,12 @@ pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue
|
||||
// Queries marked with `fatal_cycle` do not need the latter implementation,
|
||||
// as they will raise an fatal error on query cycles instead.
|
||||
rustc_queries! {
|
||||
/// This exists purely for testing the interactions between delay_span_bug and incremental.
|
||||
query trigger_delay_span_bug(key: DefId) -> () {
|
||||
desc { "triggering a delay span bug" }
|
||||
desc { "triggering a delay span bug for testing incremental" }
|
||||
}
|
||||
|
||||
/// Collects the list of all tools registered using `#![register_tool]`.
|
||||
query registered_tools(_: ()) -> &'tcx ty::RegisteredTools {
|
||||
arena_cache
|
||||
desc { "compute registered tools for crate" }
|
||||
@ -286,6 +288,7 @@ rustc_queries! {
|
||||
}
|
||||
}
|
||||
|
||||
/// The root query triggering all analysis passes like typeck or borrowck.
|
||||
query analysis(key: ()) -> Result<(), ErrorGuaranteed> {
|
||||
eval_always
|
||||
desc { "running analysis passes on this crate" }
|
||||
@ -1778,10 +1781,17 @@ rustc_queries! {
|
||||
desc { "calculating the missing lang items in a crate" }
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
/// The visible parent map is a map from every item to a visible parent.
|
||||
/// It prefers the shortest visible path to an item.
|
||||
/// Used for diagnostics, for example path trimming.
|
||||
/// The parents are modules, enums or traits.
|
||||
query visible_parent_map(_: ()) -> &'tcx DefIdMap<DefId> {
|
||||
arena_cache
|
||||
desc { "calculating the visible parent map" }
|
||||
}
|
||||
/// Collects the "trimmed", shortest accessible paths to all items for diagnostics.
|
||||
/// See the [provider docs](`rustc_middle::ty::print::trimmed_def_paths`) for more info.
|
||||
query trimmed_def_paths(_: ()) -> &'tcx FxHashMap<DefId, Symbol> {
|
||||
arena_cache
|
||||
desc { "calculating trimmed def paths" }
|
||||
|
@ -3,7 +3,6 @@ use crate::mir;
|
||||
use crate::ty::abstract_const::CastKind;
|
||||
use crate::ty::GenericArgsRef;
|
||||
use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::HashStable;
|
||||
|
||||
@ -77,28 +76,3 @@ static_assert_size!(Expr<'_>, 24);
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||
static_assert_size!(super::ConstKind<'_>, 32);
|
||||
|
||||
/// An inference variable for a const, for use in const generics.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
|
||||
pub enum InferConst {
|
||||
/// Infer the value of the const.
|
||||
Var(ty::ConstVid),
|
||||
/// Infer the value of the effect.
|
||||
///
|
||||
/// For why this is separate from the `Var` variant above, see the
|
||||
/// documentation on `EffectVid`.
|
||||
EffectVar(ty::EffectVid),
|
||||
/// A fresh const variable. See `infer::freshen` for more details.
|
||||
Fresh(u32),
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for InferConst {
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
match self {
|
||||
InferConst::Var(_) | InferConst::EffectVar(_) => {
|
||||
panic!("const variables should not be hashed: {self:?}")
|
||||
}
|
||||
InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,9 @@ use crate::traits::solve::{
|
||||
};
|
||||
use crate::ty::{
|
||||
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind,
|
||||
ImplPolarity, InferTy, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig,
|
||||
Predicate, PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind,
|
||||
TyVid, TypeAndMut, Visibility,
|
||||
ImplPolarity, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate,
|
||||
PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid,
|
||||
TypeAndMut, Visibility,
|
||||
};
|
||||
use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
|
||||
use rustc_ast::{self as ast, attr};
|
||||
@ -95,7 +95,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
type ParamTy = ParamTy;
|
||||
type BoundTy = ty::BoundTy;
|
||||
type PlaceholderTy = ty::PlaceholderType;
|
||||
type InferTy = InferTy;
|
||||
|
||||
type ErrorGuaranteed = ErrorGuaranteed;
|
||||
type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
|
||||
@ -103,7 +102,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
type AllocId = crate::mir::interpret::AllocId;
|
||||
|
||||
type Const = ty::Const<'tcx>;
|
||||
type InferConst = ty::InferConst;
|
||||
type AliasConst = ty::UnevaluatedConst<'tcx>;
|
||||
type PlaceholderConst = ty::PlaceholderConst;
|
||||
type ParamConst = ty::ParamConst;
|
||||
|
@ -84,9 +84,7 @@ pub use self::closure::{
|
||||
CapturedPlace, ClosureKind, ClosureTypeInfo, MinCaptureInformationMap, MinCaptureList,
|
||||
RootVariableMinCaptureList, UpvarCapture, UpvarId, UpvarPath, CAPTURE_STRUCT_LOCAL,
|
||||
};
|
||||
pub use self::consts::{
|
||||
Const, ConstData, ConstInt, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree,
|
||||
};
|
||||
pub use self::consts::{Const, ConstData, ConstInt, Expr, ScalarInt, UnevaluatedConst, ValTree};
|
||||
pub use self::context::{
|
||||
tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed,
|
||||
};
|
||||
@ -98,7 +96,7 @@ pub use self::sty::BoundRegionKind::*;
|
||||
pub use self::sty::{
|
||||
AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar,
|
||||
BoundVariableKind, CanonicalPolyFnSig, ClauseKind, ClosureArgs, ClosureArgsParts, ConstKind,
|
||||
ConstVid, CoroutineArgs, CoroutineArgsParts, EarlyParamRegion, EffectVid, ExistentialPredicate,
|
||||
CoroutineArgs, CoroutineArgsParts, EarlyParamRegion, ExistentialPredicate,
|
||||
ExistentialProjection, ExistentialTraitRef, FnSig, GenSig, InlineConstArgs,
|
||||
InlineConstArgsParts, LateParamRegion, ParamConst, ParamTy, PolyExistentialPredicate,
|
||||
PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef,
|
||||
|
@ -3018,7 +3018,8 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
|
||||
/// The implementation uses similar import discovery logic to that of 'use' suggestions.
|
||||
///
|
||||
/// See also [`DelayDm`](rustc_error_messages::DelayDm) and [`with_no_trimmed_paths!`].
|
||||
fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
|
||||
// this is pub to be able to intra-doc-link it
|
||||
pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
|
||||
let mut map: FxHashMap<DefId, Symbol> = FxHashMap::default();
|
||||
|
||||
if let TrimmedDefPaths::GoodPath = tcx.sess.opts.trimmed_def_paths {
|
||||
|
@ -202,34 +202,6 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ty::InferConst {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
InferConst::Var(var) => write!(f, "{var:?}"),
|
||||
InferConst::EffectVar(var) => write!(f, "{var:?}"),
|
||||
InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst {
|
||||
fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
|
||||
this: WithInfcx<'_, Infcx, &Self>,
|
||||
f: &mut core::fmt::Formatter<'_>,
|
||||
) -> core::fmt::Result {
|
||||
use ty::InferConst::*;
|
||||
match this.infcx.universe_of_ct(*this.data) {
|
||||
None => write!(f, "{:?}", this.data),
|
||||
Some(universe) => match *this.data {
|
||||
Var(vid) => write!(f, "?{}_{}c", vid.index(), universe.index()),
|
||||
EffectVar(vid) => write!(f, "?{}_{}e", vid.index(), universe.index()),
|
||||
Fresh(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
WithInfcx::with_no_infcx(self).fmt(f)
|
||||
|
@ -1608,24 +1608,6 @@ impl fmt::Debug for EarlyParamRegion {
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A **`const`** **v**ariable **ID**.
|
||||
#[debug_format = "?{}c"]
|
||||
pub struct ConstVid {}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// An **effect** **v**ariable **ID**.
|
||||
///
|
||||
/// Handling effect infer variables happens separately from const infer variables
|
||||
/// because we do not want to reuse any of the const infer machinery. If we try to
|
||||
/// relate an effect variable with a normal one, we would ICE, which can catch bugs
|
||||
/// where we are not correctly using the effect var for an effect param. Fallback
|
||||
/// is also implemented on top of having separate effect and normal const variables.
|
||||
#[debug_format = "?{}e"]
|
||||
pub struct EffectVid {}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A **region** (lifetime) **v**ariable **ID**.
|
||||
#[derive(HashStable)]
|
||||
|
@ -110,7 +110,7 @@ pub(super) trait GoalKind<'tcx>:
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
impl_def_id: DefId,
|
||||
) -> QueryResult<'tcx>;
|
||||
) -> Result<Candidate<'tcx>, NoSolution>;
|
||||
|
||||
/// If the predicate contained an error, we want to avoid emitting unnecessary trait
|
||||
/// errors but still want to emit errors for other trait goals. We have some special
|
||||
@ -263,7 +263,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
) -> Vec<Candidate<'tcx>> {
|
||||
debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
|
||||
if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
|
||||
return ambig;
|
||||
return vec![ambig];
|
||||
}
|
||||
|
||||
let mut candidates = self.assemble_candidates_via_self_ty(goal, 0);
|
||||
@ -288,15 +288,20 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
fn assemble_self_ty_infer_ambiguity_response<G: GoalKind<'tcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
) -> Option<Vec<Candidate<'tcx>>> {
|
||||
goal.predicate.self_ty().is_ty_var().then(|| {
|
||||
vec![Candidate {
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
result: self
|
||||
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
.unwrap(),
|
||||
}]
|
||||
})
|
||||
) -> Option<Candidate<'tcx>> {
|
||||
if goal.predicate.self_ty().is_ty_var() {
|
||||
debug!("adding self_ty_infer_ambiguity_response");
|
||||
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
|
||||
let result = self
|
||||
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
.unwrap();
|
||||
let mut dummy_probe = self.inspect.new_probe();
|
||||
dummy_probe.probe_kind(ProbeKind::TraitCandidate { source, result: Ok(result) });
|
||||
self.inspect.finish_probe(dummy_probe);
|
||||
Some(Candidate { source, result })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Assemble candidates which apply to the self type. This only looks at candidate which
|
||||
@ -310,7 +315,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
) -> Vec<Candidate<'tcx>> {
|
||||
debug_assert_eq!(goal, self.resolve_vars_if_possible(goal));
|
||||
if let Some(ambig) = self.assemble_self_ty_infer_ambiguity_response(goal) {
|
||||
return ambig;
|
||||
return vec![ambig];
|
||||
}
|
||||
|
||||
let mut candidates = Vec::new();
|
||||
@ -395,8 +400,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
|
||||
for &impl_def_id in impls_for_type {
|
||||
match G::consider_impl_candidate(self, goal, impl_def_id) {
|
||||
Ok(result) => candidates
|
||||
.push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
|
||||
Ok(candidate) => candidates.push(candidate),
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
}
|
||||
@ -514,8 +518,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
|
||||
for &impl_def_id in trait_impls.blanket_impls() {
|
||||
match G::consider_impl_candidate(self, goal, impl_def_id) {
|
||||
Ok(result) => candidates
|
||||
.push(Candidate { source: CandidateSource::Impl(impl_def_id), result }),
|
||||
Ok(candidate) => candidates.push(candidate),
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,10 @@
|
||||
use crate::solve::assembly::Candidate;
|
||||
|
||||
use super::EvalCtxt;
|
||||
use rustc_middle::traits::solve::{inspect, CandidateSource, QueryResult};
|
||||
use rustc_middle::traits::{
|
||||
query::NoSolution,
|
||||
solve::{inspect, CandidateSource, QueryResult},
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
|
||||
@ -36,6 +41,23 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, 'tcx, F> {
|
||||
cx: ProbeCtxt<'me, 'a, 'tcx, F, QueryResult<'tcx>>,
|
||||
source: CandidateSource,
|
||||
}
|
||||
|
||||
impl<'tcx, F> TraitProbeCtxt<'_, '_, 'tcx, F>
|
||||
where
|
||||
F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
|
||||
{
|
||||
pub(in crate::solve) fn enter(
|
||||
self,
|
||||
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||
/// `probe_kind` is only called when proof tree building is enabled so it can be
|
||||
/// as expensive as necessary to output the desired information.
|
||||
@ -69,20 +91,18 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||
pub(in crate::solve) fn probe_trait_candidate(
|
||||
&mut self,
|
||||
source: CandidateSource,
|
||||
) -> ProbeCtxt<
|
||||
'_,
|
||||
'a,
|
||||
'tcx,
|
||||
impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
|
||||
QueryResult<'tcx>,
|
||||
> {
|
||||
ProbeCtxt {
|
||||
ecx: self,
|
||||
probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::TraitCandidate {
|
||||
source,
|
||||
result: *result,
|
||||
) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>>
|
||||
{
|
||||
TraitProbeCtxt {
|
||||
cx: ProbeCtxt {
|
||||
ecx: self,
|
||||
probe_kind: move |result: &QueryResult<'tcx>| inspect::ProbeKind::TraitCandidate {
|
||||
source,
|
||||
result: *result,
|
||||
},
|
||||
_result: PhantomData,
|
||||
},
|
||||
_result: PhantomData,
|
||||
source,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::traits::{check_args_compatible, specialization_graph};
|
||||
|
||||
use super::assembly::{self, structural_traits};
|
||||
use super::assembly::{self, structural_traits, Candidate};
|
||||
use super::EvalCtxt;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -154,7 +154,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
|
||||
impl_def_id: DefId,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let tcx = ecx.tcx();
|
||||
|
||||
let goal_trait_ref = goal.predicate.projection_ty.trait_ref(tcx);
|
||||
|
@ -1,12 +1,14 @@
|
||||
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
|
||||
|
||||
use super::assembly::{self, structural_traits};
|
||||
use super::assembly::{self, structural_traits, Candidate};
|
||||
use super::{EvalCtxt, SolverMode};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{LangItem, Movability};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::inspect::ProbeKind;
|
||||
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
|
||||
use rustc_middle::traits::solve::{
|
||||
CandidateSource, CanonicalResponse, Certainty, Goal, QueryResult,
|
||||
};
|
||||
use rustc_middle::traits::{BuiltinImplSource, Reveal};
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
|
||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
|
||||
@ -38,7 +40,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||
impl_def_id: DefId,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> Result<Candidate<'tcx>, NoSolution> {
|
||||
let tcx = ecx.tcx();
|
||||
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
@ -63,7 +65,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
},
|
||||
};
|
||||
|
||||
ecx.probe_misc_candidate("impl").enter(|ecx| {
|
||||
ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
|
||||
let impl_args = ecx.fresh_args_for_item(impl_def_id);
|
||||
let impl_trait_ref = impl_trait_ref.instantiate(tcx, impl_args);
|
||||
|
||||
|
@ -25,7 +25,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{util, TraitEngine};
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal};
|
||||
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
|
||||
use rustc_middle::traits::specialization_graph::OverlapMode;
|
||||
use rustc_middle::traits::DefiningAnchor;
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
@ -397,6 +397,8 @@ fn impl_intersection_has_negative_obligation(
|
||||
) -> bool {
|
||||
debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
|
||||
|
||||
// N.B. We need to unify impl headers *with* intercrate mode, even if proving negative predicates
|
||||
// do not need intercrate mode enabled.
|
||||
let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build();
|
||||
let root_universe = infcx.universe();
|
||||
assert_eq!(root_universe, ty::UniverseIndex::ROOT);
|
||||
@ -415,13 +417,6 @@ fn impl_intersection_has_negative_obligation(
|
||||
return false;
|
||||
};
|
||||
|
||||
plug_infer_with_placeholders(
|
||||
infcx,
|
||||
root_universe,
|
||||
(impl1_header.impl_args, impl2_header.impl_args),
|
||||
);
|
||||
let param_env = infcx.resolve_vars_if_possible(param_env);
|
||||
|
||||
// FIXME(with_negative_coherence): the infcx has constraints from equating
|
||||
// the impl headers. We should use these constraints as assumptions, not as
|
||||
// requirements, when proving the negated where clauses below.
|
||||
@ -429,6 +424,13 @@ fn impl_intersection_has_negative_obligation(
|
||||
drop(infcx.take_registered_region_obligations());
|
||||
drop(infcx.take_and_reset_region_constraints());
|
||||
|
||||
plug_infer_with_placeholders(
|
||||
infcx,
|
||||
root_universe,
|
||||
(impl1_header.impl_args, impl2_header.impl_args),
|
||||
);
|
||||
let param_env = infcx.resolve_vars_if_possible(param_env);
|
||||
|
||||
util::elaborate(tcx, tcx.predicates_of(impl2_def_id).instantiate(tcx, impl2_header.impl_args))
|
||||
.any(|(clause, _)| try_prove_negated_where_clause(infcx, clause, param_env))
|
||||
}
|
||||
@ -554,7 +556,11 @@ fn try_prove_negated_where_clause<'tcx>(
|
||||
return false;
|
||||
};
|
||||
|
||||
let ref infcx = root_infcx.fork();
|
||||
// N.B. We don't need to use intercrate mode here because we're trying to prove
|
||||
// the *existence* of a negative goal, not the non-existence of a positive goal.
|
||||
// Without this, we over-eagerly register coherence ambiguity candidates when
|
||||
// impl candidates do exist.
|
||||
let ref infcx = root_infcx.fork_with_intercrate(false);
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
|
||||
ocx.register_obligation(Obligation::new(
|
||||
@ -1019,6 +1025,28 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> {
|
||||
_ => return ControlFlow::Continue(()),
|
||||
};
|
||||
|
||||
// Add ambiguity causes for reservation impls.
|
||||
for cand in goal.candidates() {
|
||||
if let inspect::ProbeKind::TraitCandidate {
|
||||
source: CandidateSource::Impl(def_id),
|
||||
result: Ok(_),
|
||||
} = cand.kind()
|
||||
{
|
||||
if let ty::ImplPolarity::Reservation = infcx.tcx.impl_polarity(def_id) {
|
||||
let value = infcx
|
||||
.tcx
|
||||
.get_attr(def_id, sym::rustc_reservation_impl)
|
||||
.and_then(|a| a.value_str());
|
||||
if let Some(value) = value {
|
||||
self.causes.insert(IntercrateAmbiguityCause::ReservationImpl {
|
||||
message: value.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add ambiguity causes for unknowable goals.
|
||||
let mut ambiguity_cause = None;
|
||||
for cand in goal.candidates() {
|
||||
// FIXME: boiiii, using string comparisions here sure is scuffed.
|
||||
|
@ -22,7 +22,7 @@ pub enum ConstKind<I: Interner> {
|
||||
Param(I::ParamConst),
|
||||
|
||||
/// Infer the value of the const.
|
||||
Infer(I::InferConst),
|
||||
Infer(InferConst),
|
||||
|
||||
/// Bound const variable, used only when preparing a trait query.
|
||||
Bound(DebruijnIndex, I::BoundConst),
|
||||
@ -65,7 +65,6 @@ const fn const_kind_discriminant<I: Interner>(value: &ConstKind<I>) -> usize {
|
||||
impl<CTX: crate::HashStableContext, I: Interner> HashStable<CTX> for ConstKind<I>
|
||||
where
|
||||
I::ParamConst: HashStable<CTX>,
|
||||
I::InferConst: HashStable<CTX>,
|
||||
I::BoundConst: HashStable<CTX>,
|
||||
I::PlaceholderConst: HashStable<CTX>,
|
||||
I::AliasConst: HashStable<CTX>,
|
||||
@ -136,3 +135,77 @@ impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A **`const`** **v**ariable **ID**.
|
||||
#[debug_format = "?{}c"]
|
||||
#[gate_rustc_only]
|
||||
pub struct ConstVid {}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// An **effect** **v**ariable **ID**.
|
||||
///
|
||||
/// Handling effect infer variables happens separately from const infer variables
|
||||
/// because we do not want to reuse any of the const infer machinery. If we try to
|
||||
/// relate an effect variable with a normal one, we would ICE, which can catch bugs
|
||||
/// where we are not correctly using the effect var for an effect param. Fallback
|
||||
/// is also implemented on top of having separate effect and normal const variables.
|
||||
#[debug_format = "?{}e"]
|
||||
#[gate_rustc_only]
|
||||
pub struct EffectVid {}
|
||||
}
|
||||
|
||||
/// An inference variable for a const, for use in const generics.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))]
|
||||
pub enum InferConst {
|
||||
/// Infer the value of the const.
|
||||
Var(ConstVid),
|
||||
/// Infer the value of the effect.
|
||||
///
|
||||
/// For why this is separate from the `Var` variant above, see the
|
||||
/// documentation on `EffectVid`.
|
||||
EffectVar(EffectVid),
|
||||
/// A fresh const variable. See `infer::freshen` for more details.
|
||||
Fresh(u32),
|
||||
}
|
||||
|
||||
impl fmt::Debug for InferConst {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
InferConst::Var(var) => write!(f, "{var:?}"),
|
||||
InferConst::EffectVar(var) => write!(f, "{var:?}"),
|
||||
InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<I: Interner> DebugWithInfcx<I> for InferConst {
|
||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
||||
this: WithInfcx<'_, Infcx, &Self>,
|
||||
f: &mut core::fmt::Formatter<'_>,
|
||||
) -> core::fmt::Result {
|
||||
match this.infcx.universe_of_ct(*this.data) {
|
||||
None => write!(f, "{:?}", this.data),
|
||||
Some(universe) => match *this.data {
|
||||
InferConst::Var(vid) => write!(f, "?{}_{}c", vid.index(), universe.index()),
|
||||
InferConst::EffectVar(vid) => write!(f, "?{}_{}e", vid.index(), universe.index()),
|
||||
InferConst::Fresh(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl<CTX> HashStable<CTX> for InferConst {
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
match self {
|
||||
InferConst::Var(_) | InferConst::EffectVar(_) => {
|
||||
panic!("const variables should not be hashed: {self:?}")
|
||||
}
|
||||
InferConst::Fresh(i) => i.hash_stable(hcx, hasher),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{Interner, UniverseIndex};
|
||||
use crate::{InferConst, InferTy, Interner, UniverseIndex};
|
||||
|
||||
use core::fmt;
|
||||
use std::marker::PhantomData;
|
||||
@ -6,15 +6,14 @@ use std::marker::PhantomData;
|
||||
pub trait InferCtxtLike {
|
||||
type Interner: Interner;
|
||||
|
||||
fn universe_of_ty(&self, ty: <Self::Interner as Interner>::InferTy) -> Option<UniverseIndex>;
|
||||
fn universe_of_ty(&self, ty: InferTy) -> Option<UniverseIndex>;
|
||||
|
||||
fn universe_of_lt(
|
||||
&self,
|
||||
lt: <Self::Interner as Interner>::InferRegion,
|
||||
) -> Option<UniverseIndex>;
|
||||
|
||||
fn universe_of_ct(&self, ct: <Self::Interner as Interner>::InferConst)
|
||||
-> Option<UniverseIndex>;
|
||||
fn universe_of_ct(&self, ct: InferConst) -> Option<UniverseIndex>;
|
||||
}
|
||||
|
||||
pub struct NoInfcx<I>(PhantomData<I>);
|
||||
@ -22,11 +21,11 @@ pub struct NoInfcx<I>(PhantomData<I>);
|
||||
impl<I: Interner> InferCtxtLike for NoInfcx<I> {
|
||||
type Interner = I;
|
||||
|
||||
fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> {
|
||||
fn universe_of_ty(&self, _ty: InferTy) -> Option<UniverseIndex> {
|
||||
None
|
||||
}
|
||||
|
||||
fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> {
|
||||
fn universe_of_ct(&self, _ct: InferConst) -> Option<UniverseIndex> {
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,6 @@ pub trait Interner: Sized {
|
||||
type ParamTy: Clone + Debug + Hash + Ord;
|
||||
type BoundTy: Clone + Debug + Hash + Ord;
|
||||
type PlaceholderTy: Clone + Debug + Hash + Ord;
|
||||
type InferTy: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||
|
||||
// Things stored inside of tys
|
||||
type ErrorGuaranteed: Clone + Debug + Hash + Ord;
|
||||
@ -37,7 +36,6 @@ pub trait Interner: Sized {
|
||||
|
||||
// Kinds of consts
|
||||
type Const: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||
type InferConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||
type AliasConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||
type PlaceholderConst: Clone + Debug + Hash + Ord;
|
||||
type ParamConst: Clone + Debug + Hash + Ord;
|
||||
|
@ -281,7 +281,7 @@ pub enum TyKind<I: Interner> {
|
||||
/// correctly deal with higher ranked types. Though unlike placeholders,
|
||||
/// that universe is stored in the `InferCtxt` instead of directly
|
||||
/// inside of the type.
|
||||
Infer(I::InferTy),
|
||||
Infer(InferTy),
|
||||
|
||||
/// A placeholder for a type which could not be computed; this is
|
||||
/// propagated to avoid useless error messages.
|
||||
@ -491,7 +491,6 @@ where
|
||||
I::BoundTy: HashStable<CTX>,
|
||||
I::ParamTy: HashStable<CTX>,
|
||||
I::PlaceholderTy: HashStable<CTX>,
|
||||
I::InferTy: HashStable<CTX>,
|
||||
I::ErrorGuaranteed: HashStable<CTX>,
|
||||
{
|
||||
#[inline]
|
||||
@ -922,7 +921,7 @@ impl fmt::Debug for InferTy {
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy {
|
||||
impl<I: Interner> DebugWithInfcx<I> for InferTy {
|
||||
fn fmt<Infcx: InferCtxtLike<Interner = I>>(
|
||||
this: WithInfcx<'_, Infcx, &Self>,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
|
@ -77,6 +77,8 @@ LL | reg.register_univ(Box::new(CapturePass::new(®.sess_mut)));
|
||||
| | | immutable borrow occurs here
|
||||
| | cast requires that `reg.sess_mut` is borrowed for `'a`
|
||||
| mutable borrow occurs here
|
||||
|
|
||||
= note: due to object lifetime defaults, `Box<dyn for<'b> LateLintPass<'b>>` actually means `Box<(dyn for<'b> LateLintPass<'b> + 'static)>`
|
||||
|
||||
error[E0502]: cannot borrow `*reg` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/two-phase-surprise-no-conflict.rs:144:5
|
||||
@ -119,6 +121,8 @@ LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut)));
|
||||
| | | first mutable borrow occurs here
|
||||
| | cast requires that `reg.sess_mut` is borrowed for `'a`
|
||||
| second mutable borrow occurs here
|
||||
|
|
||||
= note: due to object lifetime defaults, `Box<dyn for<'b> LateLintPass<'b>>` actually means `Box<(dyn for<'b> LateLintPass<'b> + 'static)>`
|
||||
|
||||
error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time
|
||||
--> $DIR/two-phase-surprise-no-conflict.rs:158:53
|
||||
|
@ -1,5 +1,9 @@
|
||||
// revisions: stock with_negative_coherence
|
||||
|
||||
//[with_negative_coherence] known-bug: unknown
|
||||
// Ideally this would work, but we don't use `&'a T` to imply that `T: 'a`
|
||||
// which is required for `&'a T: !MyPredicate` to hold. This is similar to the
|
||||
// test `negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr`
|
||||
|
||||
#![feature(negative_impls)]
|
||||
#![cfg_attr(with_negative_coherence, feature(with_negative_coherence))]
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0119]: conflicting implementations of trait `MyTrait<'_>` for type `&_`
|
||||
--> $DIR/coherence-negative-outlives-lifetimes.rs:14:1
|
||||
--> $DIR/coherence-negative-outlives-lifetimes.rs:18:1
|
||||
|
|
||||
LL | impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {}
|
||||
| ---------------------------------------------- first implementation here
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0119]: conflicting implementations of trait `MyTrait<'_>` for type `&_`
|
||||
--> $DIR/coherence-negative-outlives-lifetimes.rs:14:1
|
||||
--> $DIR/coherence-negative-outlives-lifetimes.rs:18:1
|
||||
|
|
||||
LL | impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {}
|
||||
| ---------------------------------------------- first implementation here
|
||||
|
@ -1,10 +1,4 @@
|
||||
// known-bug: unknown
|
||||
|
||||
// This fails because we currently perform negative coherence in coherence mode.
|
||||
// This means that when looking for a negative predicate, we also assemble a
|
||||
// coherence-unknowable predicate. Since confirming the negative impl has region
|
||||
// obligations, we don't prefer the impl over the unknowable predicate
|
||||
// unconditionally and instead flounder.
|
||||
// check-pass
|
||||
|
||||
#![feature(negative_impls)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
@ -1,11 +0,0 @@
|
||||
error[E0119]: conflicting implementations of trait `Bar` for type `&_`
|
||||
--> $DIR/coherence-overlap-with-regions.rs:20:1
|
||||
|
|
||||
LL | impl<T: Foo> Bar for T {}
|
||||
| ---------------------- first implementation here
|
||||
LL | impl<T> Bar for &T where T: 'static {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
@ -1,5 +1,5 @@
|
||||
error[E0119]: conflicting implementations of trait `Bar` for type `&_`
|
||||
--> $DIR/negative-coherence-considering-regions.rs:22:1
|
||||
--> $DIR/negative-coherence-considering-regions.rs:16:1
|
||||
|
|
||||
LL | impl<T> Bar for T where T: Foo {}
|
||||
| ------------------------------ first implementation here
|
||||
|
@ -1,11 +1,5 @@
|
||||
// revisions: any_lt static_lt
|
||||
//[static_lt] known-bug: unknown
|
||||
|
||||
// This fails because we currently perform negative coherence in coherence mode.
|
||||
// This means that when looking for a negative predicate, we also assemble a
|
||||
// coherence-unknowable predicate. Since confirming the negative impl has region
|
||||
// obligations, we don't prefer the impl over the unknowable predicate
|
||||
// unconditionally and instead flounder.
|
||||
//[static_lt] check-pass
|
||||
|
||||
#![feature(negative_impls)]
|
||||
#![feature(with_negative_coherence)]
|
||||
|
@ -1,12 +0,0 @@
|
||||
error[E0119]: conflicting implementations of trait `Bar` for type `&'static _`
|
||||
--> $DIR/negative-coherence-considering-regions.rs:26:1
|
||||
|
|
||||
LL | impl<T> Bar for T where T: Foo {}
|
||||
| ------------------------------ first implementation here
|
||||
...
|
||||
LL | impl<T> Bar for &'static T {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&'static _`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
@ -8,6 +8,8 @@ LL | o1.set0(&o2);
|
||||
...
|
||||
LL | }
|
||||
| - `o2` dropped here while still borrowed
|
||||
|
|
||||
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
|
||||
|
||||
error[E0597]: `o3` does not live long enough
|
||||
--> $DIR/dropck_trait_cycle_checked.rs:112:13
|
||||
@ -20,6 +22,8 @@ LL | o1.set1(&o3);
|
||||
...
|
||||
LL | }
|
||||
| - `o3` dropped here while still borrowed
|
||||
|
|
||||
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
|
||||
|
||||
error[E0597]: `o2` does not live long enough
|
||||
--> $DIR/dropck_trait_cycle_checked.rs:113:13
|
||||
@ -32,6 +36,8 @@ LL | o2.set0(&o2);
|
||||
...
|
||||
LL | }
|
||||
| - `o2` dropped here while still borrowed
|
||||
|
|
||||
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
|
||||
|
||||
error[E0597]: `o3` does not live long enough
|
||||
--> $DIR/dropck_trait_cycle_checked.rs:114:13
|
||||
@ -44,6 +50,8 @@ LL | o2.set1(&o3);
|
||||
...
|
||||
LL | }
|
||||
| - `o3` dropped here while still borrowed
|
||||
|
|
||||
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
|
||||
|
||||
error[E0597]: `o1` does not live long enough
|
||||
--> $DIR/dropck_trait_cycle_checked.rs:115:13
|
||||
@ -56,6 +64,8 @@ LL | o3.set0(&o1);
|
||||
LL | o3.set1(&o2);
|
||||
LL | }
|
||||
| - `o1` dropped here while still borrowed
|
||||
|
|
||||
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
|
||||
|
||||
error[E0597]: `o2` does not live long enough
|
||||
--> $DIR/dropck_trait_cycle_checked.rs:116:13
|
||||
@ -67,6 +77,8 @@ LL | o3.set1(&o2);
|
||||
| ^^^ borrowed value does not live long enough
|
||||
LL | }
|
||||
| - `o2` dropped here while still borrowed
|
||||
|
|
||||
= note: due to object lifetime defaults, `Box<dyn Obj<'_>>` actually means `Box<(dyn Obj<'_> + 'static)>`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
@ -6,8 +6,6 @@ LL | impl<T: Send> AnotherTrait for T {}
|
||||
...
|
||||
LL | impl AnotherTrait for D<OpaqueType> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
|
||||
|
|
||||
= note: upstream crates may add a new impl of trait `std::marker::Send` for type `OpaqueType` in future versions
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo`
|
||||
--> $DIR/never-from-impl-is-reserved.rs:10:1
|
||||
--> $DIR/never-from-impl-is-reserved.rs:13:1
|
||||
|
|
||||
LL | impl MyTrait for MyFoo {}
|
||||
| ---------------------- first implementation here
|
14
tests/ui/never_type/never-from-impl-is-reserved.next.stderr
Normal file
14
tests/ui/never_type/never-from-impl-is-reserved.next.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error[E0119]: conflicting implementations of trait `MyTrait` for type `MyFoo`
|
||||
--> $DIR/never-from-impl-is-reserved.rs:13:1
|
||||
|
|
||||
LL | impl MyTrait for MyFoo {}
|
||||
| ---------------------- first implementation here
|
||||
LL | // This will conflict with the first impl if we impl `for<T> T: From<!>`.
|
||||
LL | impl<T> MyTrait for T where T: From<!> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `MyFoo`
|
||||
|
|
||||
= note: permitting this impl would forbid us from adding `impl<T> From<!> for T` later; see rust-lang/rust#64715 for details
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
@ -1,5 +1,8 @@
|
||||
// check that the `for<T> T: From<!>` impl is reserved
|
||||
|
||||
// revisions: current next
|
||||
//[next] compile-flags: -Ztrait-solver=next-coherence
|
||||
|
||||
#![feature(never_type)]
|
||||
|
||||
pub struct MyFoo;
|
||||
|
@ -0,0 +1,39 @@
|
||||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
// Proc macro helper for issue #89699, used by tests/ui/proc-macro/edition-gated-async-move-
|
||||
// syntax-issue89699.rs, emitting an `async move` closure. This syntax is only available in
|
||||
// editions 2018 and up, but is used in edition 2015 in the test.
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::*;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn foo(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let tt = item.into_iter().next().unwrap();
|
||||
let sp = tt.span();
|
||||
let mut arg = TokenStream::new();
|
||||
let mut g = Group::new(Delimiter::Brace, TokenStream::new());
|
||||
g.set_span(sp);
|
||||
arg.extend([
|
||||
TokenTree::Ident(Ident::new("async", sp)),
|
||||
TokenTree::Ident(Ident::new("move", sp)),
|
||||
TokenTree::Group(g),
|
||||
]);
|
||||
let mut body = TokenStream::new();
|
||||
body.extend([
|
||||
TokenTree::Ident(Ident::new("async_main", sp)),
|
||||
TokenTree::Group(Group::new(Delimiter::Parenthesis, arg)),
|
||||
]);
|
||||
|
||||
let mut ret = TokenStream::new();
|
||||
ret.extend([
|
||||
TokenTree::Ident(Ident::new("fn", sp)),
|
||||
TokenTree::Ident(Ident::new("main", sp)),
|
||||
TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
|
||||
TokenTree::Group(Group::new(Delimiter::Brace, body)),
|
||||
]);
|
||||
ret
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
// aux-build:edition-gated-async-move-syntax.rs
|
||||
// edition: 2015
|
||||
|
||||
// Non-regression test for issue #89699, where a proc-macro emitting syntax only available in
|
||||
// edition 2018 and up (`async move`) is used on edition 2015
|
||||
|
||||
extern crate edition_gated_async_move_syntax;
|
||||
|
||||
#[edition_gated_async_move_syntax::foo]
|
||||
fn foo() {} //~ ERROR `async move` blocks are only allowed in Rust 2018 or later
|
@ -0,0 +1,8 @@
|
||||
error: `async move` blocks are only allowed in Rust 2018 or later
|
||||
--> $DIR/edition-gated-async-move-syntax-issue89699.rs:10:1
|
||||
|
|
||||
LL | fn foo() {}
|
||||
| ^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -6,9 +6,6 @@ LL | impl<T: Copy> Trait for T {}
|
||||
LL | struct LocalTy;
|
||||
LL | impl Trait for <LocalTy as Overflow>::Assoc {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `<LocalTy as Overflow>::Assoc`
|
||||
|
|
||||
= note: downstream crates may implement trait `std::marker::Sized` for type `<LocalTy as Overflow>::Assoc`
|
||||
= note: downstream crates may implement trait `std::marker::Copy` for type `<LocalTy as Overflow>::Assoc`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -5,6 +5,8 @@ LL | impl OtherTrait for () {}
|
||||
| ---------------------- first implementation here
|
||||
LL | impl<T: MyTrait> OtherTrait for T {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
|
||||
|
|
||||
= note: this impl is reserved
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
16
tests/ui/traits/trait-object-lifetime-default-note.rs
Normal file
16
tests/ui/traits/trait-object-lifetime-default-note.rs
Normal file
@ -0,0 +1,16 @@
|
||||
trait A {}
|
||||
|
||||
impl<T> A for T {}
|
||||
|
||||
fn main() {
|
||||
let local = 0; //~ NOTE binding `local` declared here
|
||||
let r = &local; //~ ERROR `local` does not live long enough
|
||||
//~| NOTE borrowed value does not live long enough
|
||||
//~| NOTE due to object lifetime defaults, `Box<dyn A>` actually means `Box<(dyn A + 'static)>`
|
||||
require_box(Box::new(r));
|
||||
//~^ NOTE cast requires that `local` is borrowed for `'static`
|
||||
|
||||
let _ = 0;
|
||||
} //~ NOTE `local` dropped here while still borrowed
|
||||
|
||||
fn require_box(_a: Box<dyn A>) {}
|
19
tests/ui/traits/trait-object-lifetime-default-note.stderr
Normal file
19
tests/ui/traits/trait-object-lifetime-default-note.stderr
Normal file
@ -0,0 +1,19 @@
|
||||
error[E0597]: `local` does not live long enough
|
||||
--> $DIR/trait-object-lifetime-default-note.rs:7:13
|
||||
|
|
||||
LL | let local = 0;
|
||||
| ----- binding `local` declared here
|
||||
LL | let r = &local;
|
||||
| ^^^^^^ borrowed value does not live long enough
|
||||
...
|
||||
LL | require_box(Box::new(r));
|
||||
| ----------- cast requires that `local` is borrowed for `'static`
|
||||
...
|
||||
LL | }
|
||||
| - `local` dropped here while still borrowed
|
||||
|
|
||||
= note: due to object lifetime defaults, `Box<dyn A>` actually means `Box<(dyn A + 'static)>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
@ -0,0 +1,36 @@
|
||||
#![deny(deref_into_dyn_supertrait)]
|
||||
#![feature(trait_upcasting)] // remove this and the test compiles
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
trait Bar<T> {}
|
||||
impl<T, U> Bar<U> for T {}
|
||||
|
||||
trait Foo: Bar<i32> {
|
||||
fn as_dyn_bar_u32<'a>(&self) -> &(dyn Bar<u32> + 'a);
|
||||
}
|
||||
|
||||
impl Foo for () {
|
||||
fn as_dyn_bar_u32<'a>(&self) -> &(dyn Bar<u32> + 'a) {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for dyn Foo + 'a {
|
||||
type Target = dyn Bar<u32> + 'a;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.as_dyn_bar_u32()
|
||||
}
|
||||
}
|
||||
|
||||
fn take_dyn<T>(x: &dyn Bar<T>) -> T {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x: &dyn Foo = &();
|
||||
let y = take_dyn(x);
|
||||
let z: u32 = y;
|
||||
//~^ ERROR mismatched types
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/inference-behavior-change-deref.rs:34:18
|
||||
|
|
||||
LL | let z: u32 = y;
|
||||
| --- ^ expected `u32`, found `i32`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
|
||||
|
|
||||
LL | let z: u32 = y.try_into().unwrap();
|
||||
| ++++++++++++++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
18
tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs
Normal file
18
tests/ui/traits/trait-upcasting/migrate-lint-deny-regions.rs
Normal file
@ -0,0 +1,18 @@
|
||||
#![deny(deref_into_dyn_supertrait)]
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
trait Bar<'a> {}
|
||||
trait Foo<'a>: Bar<'a> {}
|
||||
|
||||
impl<'a> Deref for dyn Foo<'a> {
|
||||
//~^ ERROR dyn Foo<'_>` implements `Deref` with supertrait `Bar<'_>` as target
|
||||
//~| WARN this will change its meaning in a future release!
|
||||
type Target = dyn Bar<'a>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,19 @@
|
||||
error: `dyn Foo<'_>` implements `Deref` with supertrait `Bar<'_>` as target
|
||||
--> $DIR/migrate-lint-deny-regions.rs:8:1
|
||||
|
|
||||
LL | impl<'a> Deref for dyn Foo<'a> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | type Target = dyn Bar<'a>;
|
||||
| -------------------------- target type is set here
|
||||
|
|
||||
= warning: this will change its meaning in a future release!
|
||||
= note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
|
||||
note: the lint level is defined here
|
||||
--> $DIR/migrate-lint-deny-regions.rs:1:9
|
||||
|
|
||||
LL | #![deny(deref_into_dyn_supertrait)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,16 +1,14 @@
|
||||
#![deny(deref_into_dyn_supertrait)]
|
||||
|
||||
extern crate core;
|
||||
|
||||
use core::ops::Deref;
|
||||
use std::ops::Deref;
|
||||
|
||||
// issue 89190
|
||||
trait A {}
|
||||
trait B: A {}
|
||||
|
||||
impl<'a> Deref for dyn 'a + B {
|
||||
//~^ ERROR `(dyn B + 'a)` implements `Deref` with supertrait `A` as target
|
||||
//~| WARN this was previously accepted by the compiler but is being phased out;
|
||||
//~^ ERROR `dyn B` implements `Deref` with supertrait `A` as target
|
||||
//~| WARN this will change its meaning in a future release!
|
||||
|
||||
type Target = dyn A;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: `(dyn B + 'a)` implements `Deref` with supertrait `A` as target
|
||||
--> $DIR/migrate-lint-deny.rs:11:1
|
||||
error: `dyn B` implements `Deref` with supertrait `A` as target
|
||||
--> $DIR/migrate-lint-deny.rs:9:1
|
||||
|
|
||||
LL | impl<'a> Deref for dyn 'a + B {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -7,7 +7,7 @@ LL | impl<'a> Deref for dyn 'a + B {
|
||||
LL | type Target = dyn A;
|
||||
| -------------------- target type is set here
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= warning: this will change its meaning in a future release!
|
||||
= note: for more information, see issue #89460 <https://github.com/rust-lang/rust/issues/89460>
|
||||
note: the lint level is defined here
|
||||
--> $DIR/migrate-lint-deny.rs:1:9
|
||||
|
@ -1,7 +1,7 @@
|
||||
// compile-flags: -Ztreat-err-as-bug
|
||||
// failure-status: 101
|
||||
// error-pattern: aborting due to `-Z treat-err-as-bug=1`
|
||||
// error-pattern: [trigger_delay_span_bug] triggering a delay span bug
|
||||
// error-pattern: [trigger_delay_span_bug] triggering a delay span bug for testing incremental
|
||||
// normalize-stderr-test "note: .*\n\n" -> ""
|
||||
// normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> ""
|
||||
// rustc-env:RUST_BACKTRACE=0
|
||||
|
@ -7,5 +7,5 @@ LL | fn main() {}
|
||||
error: the compiler unexpectedly panicked. this is a bug.
|
||||
|
||||
query stack during panic:
|
||||
#0 [trigger_delay_span_bug] triggering a delay span bug
|
||||
#0 [trigger_delay_span_bug] triggering a delay span bug for testing incremental
|
||||
end of query stack
|
||||
|
@ -17,4 +17,10 @@ fn main() {
|
||||
};
|
||||
51
|
||||
}];
|
||||
|
||||
while true {
|
||||
break (|| { //~ ERROR `break` with value from a `while` loop
|
||||
let local = 9;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,21 @@ help: use `break` on its own without a value inside this `while` loop
|
||||
LL | break;
|
||||
| ~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0571]: `break` with value from a `while` loop
|
||||
--> $DIR/issue-114529-illegal-break-with-value.rs:22:9
|
||||
|
|
||||
LL | while true {
|
||||
| ---------- you can't `break` with a value in a `while` loop
|
||||
LL | / break (|| {
|
||||
LL | | let local = 9;
|
||||
LL | | });
|
||||
| |__________^ can only break with a value inside `loop` or breakable block
|
||||
|
|
||||
help: use `break` on its own without a value inside this `while` loop
|
||||
|
|
||||
LL | break;
|
||||
| ~~~~~
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0571`.
|
||||
|
Loading…
Reference in New Issue
Block a user