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:
bors 2023-11-21 02:02:30 +00:00
commit baf4abff31
54 changed files with 568 additions and 226 deletions

View File

@ -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[&param_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,

View File

@ -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 ",

View File

@ -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,

View File

@ -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);

View File

@ -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,
}
}

View File

@ -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 },
);
}

View File

@ -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.
///

View File

@ -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" }

View File

@ -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),
}
}
}

View File

@ -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;

View File

@ -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,

View File

@ -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 {

View File

@ -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)

View File

@ -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)]

View File

@ -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) => (),
}
}

View File

@ -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,
}
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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),
}
}
}

View File

@ -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
}

View File

@ -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;

View File

@ -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<'_>,

View File

@ -77,6 +77,8 @@ LL | reg.register_univ(Box::new(CapturePass::new(&reg.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

View File

@ -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))]

View File

@ -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

View File

@ -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

View File

@ -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)]

View File

@ -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`.

View File

@ -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

View File

@ -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)]

View File

@ -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`.

View File

@ -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

View File

@ -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

View File

@ -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

View 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`.

View File

@ -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;

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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>) {}

View 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`.

View File

@ -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
}

View File

@ -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`.

View 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() {}

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -17,4 +17,10 @@ fn main() {
};
51
}];
while true {
break (|| { //~ ERROR `break` with value from a `while` loop
let local = 9;
});
}
}

View File

@ -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`.