mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #155047 - jdonszelmann:lint-against-eq-typing-mode, r=lcnr
Always exhaustively match on typing mode r? @lcnr Unimplements Eq/PartialEq for TypingMode, adds TypingModeEqWrapper for the few cases where we need it (mainly in the query system), and adds a new rustc internal lint to detect cases where we non-exhaustively match on typing mode.
This commit is contained in:
@@ -1349,3 +1349,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicConstStableIndirectPar
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcExhaustiveParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcExhaustiveParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_must_match_exhaustively];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Enum)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcMustMatchExhaustively;
|
||||
}
|
||||
|
||||
@@ -297,6 +297,7 @@ mod late {
|
||||
Single<WithoutArgs<RustcEffectiveVisibilityParser>>,
|
||||
Single<WithoutArgs<RustcEiiForeignItemParser>>,
|
||||
Single<WithoutArgs<RustcEvaluateWhereClausesParser>>,
|
||||
Single<WithoutArgs<RustcExhaustiveParser>>,
|
||||
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
|
||||
Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
|
||||
Single<WithoutArgs<RustcInheritOverflowChecksParser>>,
|
||||
|
||||
@@ -103,13 +103,10 @@ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
// FIXME(#132279): Once we've got a typing mode which reveals opaque types using the HIR
|
||||
// typeck results without causing query cycles, we should use this here instead of defining
|
||||
// opaque types.
|
||||
let typing_env = ty::TypingEnv {
|
||||
typing_mode: ty::TypingMode::analysis_in_body(
|
||||
cx.tcx,
|
||||
cx.body.source.def_id().expect_local(),
|
||||
),
|
||||
param_env: cx.typing_env.param_env,
|
||||
};
|
||||
let typing_env = ty::TypingEnv::new(
|
||||
cx.typing_env.param_env,
|
||||
ty::TypingMode::analysis_in_body(cx.tcx, cx.body.source.def_id().expect_local()),
|
||||
);
|
||||
let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(typing_env);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
let obligation = Obligation::new(
|
||||
|
||||
@@ -371,10 +371,20 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
||||
// This shouldn't be used for statics, since statics are conceptually places,
|
||||
// not values -- so what we do here could break pointer identity.
|
||||
assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));
|
||||
// Const eval always happens in PostAnalysis mode . See the comment in
|
||||
// `InterpCx::new` for more details.
|
||||
debug_assert_eq!(key.typing_env.typing_mode, ty::TypingMode::PostAnalysis);
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
match key.typing_env.typing_mode() {
|
||||
ty::TypingMode::PostAnalysis => {}
|
||||
ty::TypingMode::Coherence
|
||||
| ty::TypingMode::Analysis { .. }
|
||||
| ty::TypingMode::Borrowck { .. }
|
||||
| ty::TypingMode::PostBorrowckAnalysis { .. } => {
|
||||
bug!(
|
||||
"Const eval should always happens in PostAnalysis mode. See the comment in `InterpCx::new` for more details."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we format the instance even if we do not print it.
|
||||
// This serves as a regression test against an ICE on printing.
|
||||
// The next two lines concatenated contain some discussion:
|
||||
|
||||
@@ -236,9 +236,19 @@ pub(crate) fn eval_to_valtree<'tcx>(
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
cid: GlobalId<'tcx>,
|
||||
) -> EvalToValTreeResult<'tcx> {
|
||||
// Const eval always happens in PostAnalysis mode . See the comment in
|
||||
// `InterpCx::new` for more details.
|
||||
debug_assert_eq!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
|
||||
if cfg!(debug_assertions) {
|
||||
match typing_env.typing_mode() {
|
||||
ty::TypingMode::PostAnalysis => {}
|
||||
ty::TypingMode::Coherence
|
||||
| ty::TypingMode::Analysis { .. }
|
||||
| ty::TypingMode::Borrowck { .. }
|
||||
| ty::TypingMode::PostBorrowckAnalysis { .. } => {
|
||||
bug!(
|
||||
"Const eval should always happens in PostAnalysis mode. See the comment in `InterpCx::new` for more details."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
let const_alloc = tcx.eval_to_allocation_raw(typing_env.as_query_input(cid))?;
|
||||
|
||||
// FIXME Need to provide a span to `eval_to_valtree`
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use std::debug_assert_matches;
|
||||
|
||||
use either::{Left, Right};
|
||||
use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout};
|
||||
use rustc_hir::def_id::DefId;
|
||||
@@ -11,9 +9,10 @@
|
||||
LayoutOfHelpers, TyAndLayout,
|
||||
};
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingEnv, Variance,
|
||||
self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingEnv, TypingMode,
|
||||
Variance,
|
||||
};
|
||||
use rustc_middle::{mir, span_bug};
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::callconv::FnAbi;
|
||||
use tracing::{debug, trace};
|
||||
@@ -243,7 +242,18 @@ pub fn new(
|
||||
// opaque types. This is needed for trivial things like `size_of`, but also for using associated
|
||||
// types that are not specified in the opaque type. We also use MIR bodies whose opaque types have
|
||||
// already been revealed, so we'd be able to at least partially observe the hidden types anyways.
|
||||
debug_assert_matches!(typing_env.typing_mode, ty::TypingMode::PostAnalysis);
|
||||
if cfg!(debug_assertions) {
|
||||
match typing_env.typing_mode() {
|
||||
TypingMode::PostAnalysis => {}
|
||||
TypingMode::Coherence
|
||||
| TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. } => {
|
||||
bug!("Const eval should always happens in PostAnalysis mode.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InterpCx {
|
||||
machine,
|
||||
tcx: tcx.at(root_span),
|
||||
|
||||
@@ -1414,6 +1414,10 @@ pub struct BuiltinAttribute {
|
||||
rustc_scalable_vector, Normal, template!(List: &["count"]), WarnFollowing, EncodeCrossCrate::Yes,
|
||||
"`#[rustc_scalable_vector]` defines a scalable vector type"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_must_match_exhaustively, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
|
||||
"enums with `#[rustc_must_match_exhaustively]` must be matched on with a match block that mentions all variants explicitly"
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes, Testing:
|
||||
|
||||
@@ -1471,6 +1471,9 @@ pub enum AttributeKind {
|
||||
fn_names: ThinVec<Ident>,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_must_match_exhaustively]`
|
||||
RustcMustMatchExhaustively(Span),
|
||||
|
||||
/// Represents `#[rustc_never_returns_null_ptr]`
|
||||
RustcNeverReturnsNullPtr,
|
||||
|
||||
|
||||
@@ -156,6 +156,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
|
||||
RustcMain => No,
|
||||
RustcMir(..) => Yes,
|
||||
RustcMustImplementOneOf { .. } => No,
|
||||
RustcMustMatchExhaustively(..) => Yes,
|
||||
RustcNeverReturnsNullPtr => Yes,
|
||||
RustcNeverTypeOptions { .. } => No,
|
||||
RustcNoImplicitAutorefs => Yes,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
self, BoundVar, GenericArg, InferConst, List, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder,
|
||||
TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_type_ir::TypingModeEqWrapper;
|
||||
use smallvec::SmallVec;
|
||||
use tracing::debug;
|
||||
|
||||
@@ -72,7 +73,7 @@ pub fn canonicalize_query<V>(
|
||||
query_state,
|
||||
)
|
||||
.unchecked_map(|(param_env, value)| param_env.and(value));
|
||||
CanonicalQueryInput { canonical, typing_mode: self.typing_mode() }
|
||||
CanonicalQueryInput { canonical, typing_mode: TypingModeEqWrapper(self.typing_mode()) }
|
||||
}
|
||||
|
||||
/// Canonicalizes a query *response* `V`. When we canonicalize a
|
||||
|
||||
@@ -564,16 +564,16 @@ pub fn build_with_canonical<T>(
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let infcx = self.build(input.typing_mode);
|
||||
let infcx = self.build(input.typing_mode.0);
|
||||
let (value, args) = infcx.instantiate_canonical(span, &input.canonical);
|
||||
(infcx, value, args)
|
||||
}
|
||||
|
||||
pub fn build_with_typing_env(
|
||||
mut self,
|
||||
TypingEnv { typing_mode, param_env }: TypingEnv<'tcx>,
|
||||
typing_env: TypingEnv<'tcx>,
|
||||
) -> (InferCtxt<'tcx>, ty::ParamEnv<'tcx>) {
|
||||
(self.build(typing_mode), param_env)
|
||||
(self.build(typing_env.typing_mode()), typing_env.param_env)
|
||||
}
|
||||
|
||||
pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> {
|
||||
@@ -1376,7 +1376,7 @@ pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> {
|
||||
| ty::TypingMode::PostBorrowckAnalysis { .. }
|
||||
| ty::TypingMode::PostAnalysis) => mode,
|
||||
};
|
||||
ty::TypingEnv { typing_mode, param_env }
|
||||
ty::TypingEnv::new(param_env, typing_mode)
|
||||
}
|
||||
|
||||
/// Similar to [`Self::canonicalize_query`], except that it returns
|
||||
|
||||
@@ -89,7 +89,7 @@ pub fn handle_opaque_type(
|
||||
if def_id.is_local() =>
|
||||
{
|
||||
let def_id = def_id.expect_local();
|
||||
if let ty::TypingMode::Coherence = self.typing_mode() {
|
||||
if self.typing_mode().is_coherence() {
|
||||
// See comment on `insert_hidden_type` for why this is sufficient in coherence
|
||||
return Some(self.register_hidden_type(
|
||||
OpaqueTypeKey { def_id, args },
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::{
|
||||
self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt, TypeVisitor, TypingMode,
|
||||
TypeVisitableExt, TypeVisitor,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use tracing::{debug, instrument, warn};
|
||||
@@ -603,7 +603,7 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
//
|
||||
// cc trait-system-refactor-initiative#108
|
||||
if self.infcx.next_trait_solver()
|
||||
&& !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
|
||||
&& !self.infcx.typing_mode().is_coherence()
|
||||
&& self.in_alias
|
||||
{
|
||||
inner.type_variables().equate(vid, new_var_id);
|
||||
@@ -735,7 +735,7 @@ fn consts(
|
||||
// See the comment for type inference variables
|
||||
// for more details.
|
||||
if self.infcx.next_trait_solver()
|
||||
&& !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
|
||||
&& !self.infcx.typing_mode().is_coherence()
|
||||
&& self.in_alias
|
||||
{
|
||||
variable_table.union(vid, new_var_id);
|
||||
|
||||
@@ -637,7 +637,7 @@ pub fn typing_mode(&self) -> TypingMode<'tcx> {
|
||||
}
|
||||
|
||||
pub fn typing_env(&self) -> TypingEnv<'tcx> {
|
||||
TypingEnv { typing_mode: self.typing_mode(), param_env: self.param_env }
|
||||
TypingEnv::new(self.param_env, self.typing_mode())
|
||||
}
|
||||
|
||||
pub fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
use crate::lints::{
|
||||
AttributeKindInFindAttr, BadOptAccessDiag, DefaultHashTypesDiag,
|
||||
ImplicitSysrootCrateImportDiag, LintPassByHand, NonGlobImportTypeIrInherent, QueryInstability,
|
||||
QueryUntracked, SpanUseEqCtxtDiag, SymbolInternStringLiteralDiag, TyQualified, TykindDiag,
|
||||
TykindKind, TypeIrDirectUse, TypeIrInherentUsage, TypeIrTraitUsage,
|
||||
QueryUntracked, RustcMustMatchExhaustivelyNotExhaustive, SpanUseEqCtxtDiag,
|
||||
SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, TypeIrDirectUse,
|
||||
TypeIrInherentUsage, TypeIrTraitUsage,
|
||||
};
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
|
||||
@@ -713,3 +714,89 @@ fn find_attr_kind_in_pat(cx: &EarlyContext<'_>, pat: &Pat) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_tool_lint! {
|
||||
pub rustc::RUSTC_MUST_MATCH_EXHAUSTIVELY,
|
||||
Allow,
|
||||
"Forbids matches with wildcards, or if-let matching on enums marked with `#[rustc_must_match_exhaustively]`",
|
||||
report_in_external_macro: true
|
||||
}
|
||||
declare_lint_pass!(RustcMustMatchExhaustively => [RUSTC_MUST_MATCH_EXHAUSTIVELY]);
|
||||
|
||||
fn is_rustc_must_match_exhaustively(cx: &LateContext<'_>, id: HirId) -> Option<Span> {
|
||||
let res = cx.typeck_results();
|
||||
|
||||
let ty = res.node_type(id);
|
||||
|
||||
let ty = if let ty::Ref(_, ty, _) = ty.kind() { *ty } else { ty };
|
||||
|
||||
if let Some(adt_def) = ty.ty_adt_def()
|
||||
&& adt_def.is_enum()
|
||||
{
|
||||
find_attr!(cx.tcx, adt_def.did(), RustcMustMatchExhaustively(span) => *span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn pat_is_not_exhaustive_heuristic(pat: &hir::Pat<'_>) -> Option<(Span, &'static str)> {
|
||||
match pat.kind {
|
||||
hir::PatKind::Missing => None,
|
||||
hir::PatKind::Wild => Some((pat.span, "because of this wildcard pattern")),
|
||||
hir::PatKind::Binding(_, _, _, Some(pat)) => pat_is_not_exhaustive_heuristic(pat),
|
||||
hir::PatKind::Binding(..) => Some((pat.span, "because of this variable binding")),
|
||||
hir::PatKind::Struct(..) => None,
|
||||
hir::PatKind::TupleStruct(..) => None,
|
||||
hir::PatKind::Or(..) => None,
|
||||
hir::PatKind::Never => None,
|
||||
hir::PatKind::Tuple(..) => None,
|
||||
hir::PatKind::Box(pat) => pat_is_not_exhaustive_heuristic(&*pat),
|
||||
hir::PatKind::Deref(pat) => pat_is_not_exhaustive_heuristic(&*pat),
|
||||
hir::PatKind::Ref(pat, _, _) => pat_is_not_exhaustive_heuristic(&*pat),
|
||||
hir::PatKind::Expr(..) => None,
|
||||
hir::PatKind::Guard(..) => None,
|
||||
hir::PatKind::Range(..) => None,
|
||||
hir::PatKind::Slice(..) => None,
|
||||
hir::PatKind::Err(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for RustcMustMatchExhaustively {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
|
||||
match expr.kind {
|
||||
// This is not perfect exhaustiveness checking, that's why this is just a rustc internal
|
||||
// attribute. But it catches most reasonable cases
|
||||
hir::ExprKind::Match(expr, arms, _) => {
|
||||
if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.hir_id) {
|
||||
for arm in arms {
|
||||
if let Some((span, message)) = pat_is_not_exhaustive_heuristic(arm.pat) {
|
||||
cx.emit_span_lint(
|
||||
RUSTC_MUST_MATCH_EXHAUSTIVELY,
|
||||
expr.span,
|
||||
RustcMustMatchExhaustivelyNotExhaustive {
|
||||
attr_span,
|
||||
pat_span: span,
|
||||
message,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ExprKind::If(expr, ..) if let ExprKind::Let(expr) = expr.kind => {
|
||||
if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.init.hir_id) {
|
||||
cx.emit_span_lint(
|
||||
RUSTC_MUST_MATCH_EXHAUSTIVELY,
|
||||
expr.span,
|
||||
RustcMustMatchExhaustivelyNotExhaustive {
|
||||
attr_span,
|
||||
pat_span: expr.span,
|
||||
message: "using if let only matches on one variant (try using `match`)",
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,6 +668,8 @@ fn register_internals(store: &mut LintStore) {
|
||||
store.register_early_pass(|| Box::new(ImplicitSysrootCrateImport));
|
||||
store.register_lints(&BadUseOfFindAttr::lint_vec());
|
||||
store.register_early_pass(|| Box::new(BadUseOfFindAttr));
|
||||
store.register_lints(&RustcMustMatchExhaustively::lint_vec());
|
||||
store.register_late_pass(|_| Box::new(RustcMustMatchExhaustively));
|
||||
store.register_group(
|
||||
false,
|
||||
"rustc::internal",
|
||||
@@ -688,6 +690,7 @@ fn register_internals(store: &mut LintStore) {
|
||||
LintId::of(DIRECT_USE_OF_RUSTC_TYPE_IR),
|
||||
LintId::of(IMPLICIT_SYSROOT_CRATE_IMPORT),
|
||||
LintId::of(BAD_USE_OF_FIND_ATTR),
|
||||
LintId::of(RUSTC_MUST_MATCH_EXHAUSTIVELY),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1162,6 +1162,18 @@ pub(crate) struct ImplicitSysrootCrateImportDiag<'a> {
|
||||
#[help("remove `AttributeKind`")]
|
||||
pub(crate) struct AttributeKindInFindAttr;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("match is not exhaustive")]
|
||||
#[help("explicitly list all variants of the enum in a `match`")]
|
||||
pub(crate) struct RustcMustMatchExhaustivelyNotExhaustive {
|
||||
#[label("required because of this attribute")]
|
||||
pub attr_span: Span,
|
||||
|
||||
#[note("{$message}")]
|
||||
pub pat_span: Span,
|
||||
pub message: &'static str,
|
||||
}
|
||||
|
||||
// let_underscore.rs
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum NonBindingLet {
|
||||
|
||||
@@ -415,10 +415,10 @@ pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'
|
||||
pub fn typing_env(&self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
|
||||
match self.phase {
|
||||
// FIXME(#132279): we should reveal the opaques defined in the body during analysis.
|
||||
MirPhase::Built | MirPhase::Analysis(_) => TypingEnv {
|
||||
typing_mode: ty::TypingMode::non_body_analysis(),
|
||||
param_env: tcx.param_env(self.source.def_id()),
|
||||
},
|
||||
MirPhase::Built | MirPhase::Analysis(_) => TypingEnv::new(
|
||||
tcx.param_env(self.source.def_id()),
|
||||
ty::TypingMode::non_body_analysis(),
|
||||
),
|
||||
MirPhase::Runtime(_) => TypingEnv::post_analysis(tcx, self.source.def_id()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,8 @@
|
||||
AliasTy, AliasTyKind, Article, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy,
|
||||
BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig,
|
||||
InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PlaceholderConst,
|
||||
PlaceholderRegion, PlaceholderType, PolyFnSig, TyKind, TypeAndMut, TypingMode, UpvarArgs,
|
||||
PlaceholderRegion, PlaceholderType, PolyFnSig, TyKind, TypeAndMut, TypingMode,
|
||||
TypingModeEqWrapper, UpvarArgs,
|
||||
};
|
||||
pub use self::trait_def::TraitDef;
|
||||
pub use self::typeck_results::{
|
||||
@@ -980,11 +981,19 @@ pub struct ParamEnvAnd<'tcx, T> {
|
||||
pub struct TypingEnv<'tcx> {
|
||||
#[type_foldable(identity)]
|
||||
#[type_visitable(ignore)]
|
||||
pub typing_mode: TypingMode<'tcx>,
|
||||
typing_mode: TypingModeEqWrapper<'tcx>,
|
||||
pub param_env: ParamEnv<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypingEnv<'tcx> {
|
||||
pub fn new(param_env: ParamEnv<'tcx>, typing_mode: TypingMode<'tcx>) -> Self {
|
||||
Self { typing_mode: TypingModeEqWrapper(typing_mode), param_env }
|
||||
}
|
||||
|
||||
pub fn typing_mode(&self) -> TypingMode<'tcx> {
|
||||
self.typing_mode.0
|
||||
}
|
||||
|
||||
/// Create a typing environment with no where-clauses in scope
|
||||
/// where all opaque types and default associated items are revealed.
|
||||
///
|
||||
@@ -993,7 +1002,7 @@ impl<'tcx> TypingEnv<'tcx> {
|
||||
/// use `TypingMode::PostAnalysis`, they may still have where-clauses
|
||||
/// in scope.
|
||||
pub fn fully_monomorphized() -> TypingEnv<'tcx> {
|
||||
TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env: ParamEnv::empty() }
|
||||
Self::new(ParamEnv::empty(), TypingMode::PostAnalysis)
|
||||
}
|
||||
|
||||
/// Create a typing environment for use during analysis outside of a body.
|
||||
@@ -1006,7 +1015,7 @@ pub fn non_body_analysis(
|
||||
def_id: impl IntoQueryKey<DefId>,
|
||||
) -> TypingEnv<'tcx> {
|
||||
let def_id = def_id.into_query_key();
|
||||
TypingEnv { typing_mode: TypingMode::non_body_analysis(), param_env: tcx.param_env(def_id) }
|
||||
Self::new(tcx.param_env(def_id), TypingMode::non_body_analysis())
|
||||
}
|
||||
|
||||
pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryKey<DefId>) -> TypingEnv<'tcx> {
|
||||
@@ -1018,8 +1027,12 @@ pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryKey<DefId>) -> Typ
|
||||
/// opaque types in the `param_env`.
|
||||
pub fn with_post_analysis_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> {
|
||||
let TypingEnv { typing_mode, param_env } = self;
|
||||
if let TypingMode::PostAnalysis = typing_mode {
|
||||
return self;
|
||||
match typing_mode.0 {
|
||||
TypingMode::Coherence
|
||||
| TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. } => {}
|
||||
TypingMode::PostAnalysis => return self,
|
||||
}
|
||||
|
||||
// No need to reveal opaques with the new solver enabled,
|
||||
@@ -1029,7 +1042,7 @@ pub fn with_post_analysis_normalized(self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx>
|
||||
} else {
|
||||
ParamEnv::new(tcx.reveal_opaque_types_in_bounds(param_env.caller_bounds()))
|
||||
};
|
||||
TypingEnv { typing_mode: TypingMode::PostAnalysis, param_env }
|
||||
TypingEnv { typing_mode: TypingModeEqWrapper(TypingMode::PostAnalysis), param_env }
|
||||
}
|
||||
|
||||
/// Combine this typing environment with the given `value` to be used by
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>;
|
||||
pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>;
|
||||
pub type TypingMode<'tcx> = ir::TypingMode<TyCtxt<'tcx>>;
|
||||
pub type TypingModeEqWrapper<'tcx> = ir::TypingModeEqWrapper<TyCtxt<'tcx>>;
|
||||
pub type Placeholder<'tcx, T> = ir::Placeholder<TyCtxt<'tcx>, T>;
|
||||
pub type PlaceholderRegion<'tcx> = ir::PlaceholderRegion<TyCtxt<'tcx>>;
|
||||
pub type PlaceholderType<'tcx> = ir::PlaceholderType<TyCtxt<'tcx>>;
|
||||
|
||||
@@ -548,7 +548,16 @@ fn move_paths_for_fields(
|
||||
let subpath = self.elaborator.field_subpath(variant_path, field_idx);
|
||||
let tcx = self.tcx();
|
||||
|
||||
assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis);
|
||||
match self.elaborator.typing_env().typing_mode() {
|
||||
ty::TypingMode::PostAnalysis => {}
|
||||
ty::TypingMode::Coherence
|
||||
| ty::TypingMode::Analysis { .. }
|
||||
| ty::TypingMode::Borrowck { .. }
|
||||
| ty::TypingMode::PostBorrowckAnalysis { .. } => {
|
||||
bug!()
|
||||
}
|
||||
}
|
||||
|
||||
let field_ty = field.ty(tcx, args);
|
||||
// We silently leave an unnormalized type here to support polymorphic drop
|
||||
// elaboration for users of rustc internal APIs
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use rustc_type_ir::relate::solver_relating::RelateExt;
|
||||
use rustc_type_ir::{
|
||||
self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner,
|
||||
TypeFoldable,
|
||||
TypeFoldable, TypingModeEqWrapper,
|
||||
};
|
||||
use tracing::instrument;
|
||||
|
||||
@@ -66,7 +66,10 @@ pub(super) fn canonicalize_goal<D, I>(
|
||||
predefined_opaques_in_body: delegate.cx().mk_predefined_opaques_in_body(opaque_types),
|
||||
},
|
||||
);
|
||||
let query_input = ty::CanonicalQueryInput { canonical, typing_mode: delegate.typing_mode() };
|
||||
let query_input = ty::CanonicalQueryInput {
|
||||
canonical,
|
||||
typing_mode: TypingModeEqWrapper(delegate.typing_mode()),
|
||||
};
|
||||
(orig_values, query_input)
|
||||
}
|
||||
|
||||
|
||||
@@ -466,15 +466,20 @@ pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
|
||||
// as we may want to weaken inference guidance in the future and don't want
|
||||
// to worry about causing major performance regressions when doing so.
|
||||
// See trait-system-refactor-initiative#226 for some ideas here.
|
||||
if TypingMode::Coherence == self.typing_mode()
|
||||
|| !candidates.iter().any(|c| {
|
||||
let assemble_impls = match self.typing_mode() {
|
||||
TypingMode::Coherence => true,
|
||||
TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. }
|
||||
| TypingMode::PostAnalysis => !candidates.iter().any(|c| {
|
||||
matches!(
|
||||
c.source,
|
||||
CandidateSource::ParamEnv(ParamEnvSource::NonGlobal)
|
||||
| CandidateSource::AliasBound(_)
|
||||
) && has_no_inference_or_external_constraints(c.result)
|
||||
})
|
||||
{
|
||||
}),
|
||||
};
|
||||
if assemble_impls {
|
||||
self.assemble_impl_candidates(goal, &mut candidates);
|
||||
self.assemble_object_bound_candidates(goal, &mut candidates);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,9 @@ pub(super) fn normalize_opaque_type(
|
||||
});
|
||||
self.eq(goal.param_env, expected, actual)?;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
TypingMode::Coherence
|
||||
| TypingMode::PostBorrowckAnalysis { .. }
|
||||
| TypingMode::PostAnalysis => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ fn initial_provisional_result(
|
||||
// See `tests/ui/traits/next-solver/cycles/unproductive-in-coherence.rs` for an
|
||||
// example where this would matter. We likely should change these cycles to `NoSolution`
|
||||
// even in coherence once this is a bit more settled.
|
||||
PathKind::Inductive => match input.typing_mode {
|
||||
PathKind::Inductive => match input.typing_mode.0 {
|
||||
TypingMode::Coherence => {
|
||||
response_no_constraints(cx, input, Certainty::overflow(false))
|
||||
}
|
||||
|
||||
@@ -1421,7 +1421,7 @@ pub(super) fn merge_trait_candidates(
|
||||
mut candidates: Vec<Candidate<I>>,
|
||||
failed_candidate_info: FailedCandidateInfo,
|
||||
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
|
||||
if let TypingMode::Coherence = self.typing_mode() {
|
||||
if self.typing_mode().is_coherence() {
|
||||
return if let Some((response, _)) = self.try_merge_candidates(&candidates) {
|
||||
Ok((response, Some(TraitGoalProvenVia::Misc)))
|
||||
} else {
|
||||
|
||||
@@ -339,6 +339,7 @@ fn check_attributes(
|
||||
| AttributeKind::RustcMacroTransparency(_)
|
||||
| AttributeKind::RustcMain
|
||||
| AttributeKind::RustcMir(_)
|
||||
| AttributeKind::RustcMustMatchExhaustively(..)
|
||||
| AttributeKind::RustcNeverReturnsNullPtr
|
||||
| AttributeKind::RustcNeverTypeOptions {..}
|
||||
| AttributeKind::RustcNoImplicitAutorefs
|
||||
|
||||
@@ -1753,6 +1753,7 @@
|
||||
rustc_main,
|
||||
rustc_mir,
|
||||
rustc_must_implement_one_of,
|
||||
rustc_must_match_exhaustively,
|
||||
rustc_never_returns_null_ptr,
|
||||
rustc_never_type_options,
|
||||
rustc_no_implicit_autorefs,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::ty::elaborate::elaborate;
|
||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::{self, Ty, TypingMode};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use super::SelectionContext;
|
||||
@@ -25,7 +25,7 @@ pub fn evaluate_host_effect_obligation<'tcx>(
|
||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||
obligation: &HostEffectObligation<'tcx>,
|
||||
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
||||
if selcx.infcx.typing_mode() == TypingMode::Coherence {
|
||||
if selcx.infcx.typing_mode().is_coherence() {
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
"should not select host obligation in old solver in intercrate mode"
|
||||
|
||||
@@ -841,8 +841,7 @@ fn process_trait_obligation(
|
||||
stalled_on: &mut Vec<TyOrConstInferVar>,
|
||||
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
|
||||
let infcx = self.selcx.infcx;
|
||||
if obligation.predicate.is_global() && !matches!(infcx.typing_mode(), TypingMode::Coherence)
|
||||
{
|
||||
if obligation.predicate.is_global() && !infcx.typing_mode().is_coherence() {
|
||||
// no type variables present, can use evaluation for better caching.
|
||||
// FIXME: consider caching errors too.
|
||||
if infcx.predicate_must_hold_considering_regions(obligation) {
|
||||
@@ -896,8 +895,7 @@ fn process_projection_obligation(
|
||||
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
|
||||
let tcx = self.selcx.tcx();
|
||||
let infcx = self.selcx.infcx;
|
||||
if obligation.predicate.is_global() && !matches!(infcx.typing_mode(), TypingMode::Coherence)
|
||||
{
|
||||
if obligation.predicate.is_global() && !infcx.typing_mode().is_coherence() {
|
||||
// no type variables present, can use evaluation for better caching.
|
||||
// FIXME: consider caching errors too.
|
||||
if infcx.predicate_must_hold_considering_regions(obligation) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
use rustc_infer::traits::{Obligation, PolyTraitObligation, PredicateObligation, SelectionError};
|
||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::ty::{
|
||||
self, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, TypingMode, elaborate,
|
||||
self, FieldInfo, SizedTraitKind, TraitRef, Ty, TypeVisitableExt, elaborate,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::DUMMY_SP;
|
||||
@@ -849,7 +849,7 @@ fn assemble_candidates_from_auto_impls(
|
||||
//
|
||||
// Note that this is only sound as projection candidates of opaque types
|
||||
// are always applicable for auto traits.
|
||||
} else if let TypingMode::Coherence = self.infcx.typing_mode() {
|
||||
} else if self.infcx.typing_mode().is_coherence() {
|
||||
// We do not emit auto trait candidates for opaque types in coherence.
|
||||
// Doing so can result in weird dependency cycles.
|
||||
candidates.ambiguous = true;
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cmp;
|
||||
use std::fmt::{self, Display};
|
||||
use std::ops::ControlFlow;
|
||||
use std::{assert_matches, cmp};
|
||||
|
||||
use hir::def::DefKind;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
@@ -210,8 +210,9 @@ pub fn with_query_mode(
|
||||
/// Enables tracking of intercrate ambiguity causes. See
|
||||
/// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
|
||||
pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
|
||||
assert_matches!(self.infcx.typing_mode(), TypingMode::Coherence);
|
||||
assert!(self.infcx.typing_mode().is_coherence());
|
||||
assert!(self.intercrate_ambiguity_causes.is_none());
|
||||
|
||||
self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
|
||||
debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
|
||||
}
|
||||
@@ -222,7 +223,8 @@ pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
|
||||
pub fn take_intercrate_ambiguity_causes(
|
||||
&mut self,
|
||||
) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> {
|
||||
assert_matches!(self.infcx.typing_mode(), TypingMode::Coherence);
|
||||
assert!(self.infcx.typing_mode().is_coherence());
|
||||
|
||||
self.intercrate_ambiguity_causes.take().unwrap_or_default()
|
||||
}
|
||||
|
||||
@@ -1016,7 +1018,7 @@ fn evaluate_trait_predicate_recursively<'o>(
|
||||
previous_stack: TraitObligationStackList<'o, 'tcx>,
|
||||
mut obligation: PolyTraitObligation<'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
if !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
|
||||
if !self.infcx.typing_mode().is_coherence()
|
||||
&& obligation.is_global()
|
||||
&& obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param())
|
||||
{
|
||||
@@ -2548,7 +2550,7 @@ fn match_impl(
|
||||
nested_obligations.extend(obligations);
|
||||
|
||||
if impl_trait_header.polarity == ty::ImplPolarity::Reservation
|
||||
&& !matches!(self.infcx.typing_mode(), TypingMode::Coherence)
|
||||
&& !self.infcx.typing_mode().is_coherence()
|
||||
{
|
||||
debug!("reservation impls only apply in intercrate mode");
|
||||
return Err(());
|
||||
|
||||
@@ -154,7 +154,7 @@ fn resolve_associated_item<'tcx>(
|
||||
// and the obligation is monomorphic, otherwise passes such as
|
||||
// transmute checking and polymorphic MIR optimizations could
|
||||
// get a result which isn't correct for all monomorphizations.
|
||||
match typing_env.typing_mode {
|
||||
match typing_env.typing_mode() {
|
||||
ty::TypingMode::Coherence
|
||||
| ty::TypingMode::Analysis { .. }
|
||||
| ty::TypingMode::Borrowck { .. }
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
use crate::data_structures::HashMap;
|
||||
use crate::inherent::*;
|
||||
use crate::{self as ty, Interner, TypingMode, UniverseIndex};
|
||||
use crate::{self as ty, Interner, TypingModeEqWrapper, UniverseIndex};
|
||||
|
||||
#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, V)]
|
||||
#[derive_where(Copy; I: Interner, V: Copy)]
|
||||
@@ -21,7 +21,7 @@
|
||||
)]
|
||||
pub struct CanonicalQueryInput<I: Interner, V> {
|
||||
pub canonical: Canonical<I, V>,
|
||||
pub typing_mode: TypingMode<I>,
|
||||
pub typing_mode: TypingModeEqWrapper<I>,
|
||||
}
|
||||
|
||||
impl<I: Interner, V: Eq> Eq for CanonicalQueryInput<I, V> {}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use derive_where::derive_where;
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
|
||||
@@ -18,11 +20,28 @@
|
||||
///
|
||||
/// If neither of these functions are available, feel free to reach out to
|
||||
/// t-types for help.
|
||||
#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)]
|
||||
///
|
||||
/// Because typing rules get subtly different based on what typing mode we're in,
|
||||
/// subtle enough that changing the behavior of typing modes can sometimes cause
|
||||
/// changes that we don't even have tests for, we'd like to enforce the rule that
|
||||
/// any place where we specialize behavior based on the typing mode, we match
|
||||
/// *exhaustively* on the typing mode. That way, it's easy to determine all the
|
||||
/// places that must change when anything about typing modes changes.
|
||||
///
|
||||
/// Hence, `TypingMode` does not implement `Eq`, though [`TypingModeEqWrapper`] is available
|
||||
/// in the rare case that you do need this. Most cases where this currently matters is
|
||||
/// where we pass typing modes through the query system and want to cache based on it.
|
||||
/// See also `#[rustc_must_match_exhaustively]`, which tries to detect non-exhaustive
|
||||
/// matches.
|
||||
///
|
||||
/// Since matching on typing mode to single out `Coherence` is so common, and `Coherence`
|
||||
/// is so different from the other modes: see also [`is_coherence`](TypingMode::is_coherence)
|
||||
#[derive_where(Clone, Copy, Hash, Debug; I: Interner)]
|
||||
#[cfg_attr(
|
||||
feature = "nightly",
|
||||
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
|
||||
)]
|
||||
#[cfg_attr(feature = "nightly", cfg_attr(not(bootstrap), rustc_must_match_exhaustively))]
|
||||
pub enum TypingMode<I: Interner> {
|
||||
/// When checking whether impls overlap, we check whether any obligations
|
||||
/// are guaranteed to never hold when unifying the impls. This requires us
|
||||
@@ -90,9 +109,71 @@ pub enum TypingMode<I: Interner> {
|
||||
PostAnalysis,
|
||||
}
|
||||
|
||||
impl<I: Interner> Eq for TypingMode<I> {}
|
||||
/// We want to highly discourage using equality checks on typing modes.
|
||||
/// Instead you should match, **exhaustively**, so when we ever modify the enum we get a compile
|
||||
/// error. Only use `TypingModeEqWrapper` when you really really really have to.
|
||||
/// Prefer unwrapping `TypingModeEqWrapper` in apis that should return a `TypingMode` whenever
|
||||
/// possible, and if you ever get an `TypingModeEqWrapper`, prefer unwrapping it and matching on it **exhaustively**.
|
||||
#[derive_where(Clone, Copy, Debug; I: Interner)]
|
||||
#[cfg_attr(
|
||||
feature = "nightly",
|
||||
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
|
||||
)]
|
||||
pub struct TypingModeEqWrapper<I: Interner>(pub TypingMode<I>);
|
||||
|
||||
impl<I: Interner> Hash for TypingModeEqWrapper<I> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> PartialEq for TypingModeEqWrapper<I> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self.0, other.0) {
|
||||
(TypingMode::Coherence, TypingMode::Coherence) => true,
|
||||
(
|
||||
TypingMode::Analysis { defining_opaque_types_and_generators: l },
|
||||
TypingMode::Analysis { defining_opaque_types_and_generators: r },
|
||||
) => l == r,
|
||||
(
|
||||
TypingMode::Borrowck { defining_opaque_types: l },
|
||||
TypingMode::Borrowck { defining_opaque_types: r },
|
||||
) => l == r,
|
||||
(
|
||||
TypingMode::PostBorrowckAnalysis { defined_opaque_types: l },
|
||||
TypingMode::PostBorrowckAnalysis { defined_opaque_types: r },
|
||||
) => l == r,
|
||||
(TypingMode::PostAnalysis, TypingMode::PostAnalysis) => true,
|
||||
(
|
||||
TypingMode::Coherence
|
||||
| TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. }
|
||||
| TypingMode::PostAnalysis,
|
||||
_,
|
||||
) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> Eq for TypingModeEqWrapper<I> {}
|
||||
|
||||
impl<I: Interner> TypingMode<I> {
|
||||
/// There are a bunch of places in the compiler where we single out `Coherence`,
|
||||
/// and alter behavior. We'd like to *always* match on `TypingMode` exhaustively,
|
||||
/// but not having this method leads to a bunch of noisy code.
|
||||
///
|
||||
/// See also the documentation on [`TypingMode`] about exhaustive matching.
|
||||
pub fn is_coherence(&self) -> bool {
|
||||
match self {
|
||||
TypingMode::Coherence => true,
|
||||
TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. }
|
||||
| TypingMode::PostAnalysis => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Analysis outside of a body does not define any opaque types.
|
||||
pub fn non_body_analysis() -> TypingMode<I> {
|
||||
TypingMode::Analysis { defining_opaque_types_and_generators: Default::default() }
|
||||
@@ -322,6 +403,13 @@ pub fn may_use_unstable_feature<'a, I: Interner, Infcx>(
|
||||
// Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled
|
||||
// if we are in std/core even if there is a corresponding `feature` attribute on the crate.
|
||||
|
||||
(infcx.typing_mode() == TypingMode::PostAnalysis)
|
||||
|| infcx.cx().features().feature_bound_holds_in_crate(symbol)
|
||||
match infcx.typing_mode() {
|
||||
TypingMode::Coherence
|
||||
| TypingMode::Analysis { .. }
|
||||
| TypingMode::Borrowck { .. }
|
||||
| TypingMode::PostBorrowckAnalysis { .. } => {
|
||||
infcx.cx().features().feature_bound_holds_in_crate(symbol)
|
||||
}
|
||||
TypingMode::PostAnalysis => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,10 +87,7 @@ pub(crate) fn with_param_env<T, F: FnOnce(&mut Self) -> T>(
|
||||
}
|
||||
|
||||
pub(crate) fn typing_env(&self) -> ty::TypingEnv<'tcx> {
|
||||
ty::TypingEnv {
|
||||
typing_mode: ty::TypingMode::non_body_analysis(),
|
||||
param_env: self.param_env,
|
||||
}
|
||||
ty::TypingEnv::new(self.param_env, ty::TypingMode::non_body_analysis())
|
||||
}
|
||||
|
||||
/// Call the closure with the given parameters set as
|
||||
|
||||
@@ -85,8 +85,8 @@ fn typing_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
|
||||
.upcast(tcx)
|
||||
}),
|
||||
)));
|
||||
ty::TypingEnv {
|
||||
typing_mode: ty::TypingMode::non_body_analysis(),
|
||||
ty::TypingEnv::new(
|
||||
param_env,
|
||||
}
|
||||
ty::TypingMode::non_body_analysis(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
//@ compile-flags: -Z unstable-options
|
||||
//@ ignore-stage1
|
||||
|
||||
#![feature(rustc_private)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![deny(rustc::rustc_must_match_exhaustively)]
|
||||
|
||||
#[rustc_must_match_exhaustively]
|
||||
#[derive(Copy, Clone)]
|
||||
enum Foo {
|
||||
A { field: u32 },
|
||||
B,
|
||||
}
|
||||
|
||||
fn foo(f: Foo) {
|
||||
match f {
|
||||
Foo::A { .. } => {}
|
||||
Foo::B => {}
|
||||
}
|
||||
|
||||
match f {
|
||||
//~^ ERROR match is not exhaustive
|
||||
Foo::A { .. } => {}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match f {
|
||||
//~^ ERROR match is not exhaustive
|
||||
Foo::A { .. } => {}
|
||||
a => {}
|
||||
}
|
||||
|
||||
match &f {
|
||||
//~^ ERROR match is not exhaustive
|
||||
Foo::A { .. } => {}
|
||||
a => {}
|
||||
}
|
||||
|
||||
match f {
|
||||
Foo::A { .. } => {}
|
||||
a @ Foo::B => {}
|
||||
}
|
||||
|
||||
if let Foo::A { .. } = f {}
|
||||
//~^ ERROR match is not exhaustive
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,71 @@
|
||||
error: match is not exhaustive
|
||||
--> $DIR/must_match_exhaustively.rs:21:11
|
||||
|
|
||||
LL | #[rustc_must_match_exhaustively]
|
||||
| -------------------------------- required because of this attribute
|
||||
...
|
||||
LL | match f {
|
||||
| ^
|
||||
|
|
||||
= help: explicitly list all variants of the enum in a `match`
|
||||
note: because of this wildcard pattern
|
||||
--> $DIR/must_match_exhaustively.rs:24:9
|
||||
|
|
||||
LL | _ => {}
|
||||
| ^
|
||||
note: the lint level is defined here
|
||||
--> $DIR/must_match_exhaustively.rs:6:9
|
||||
|
|
||||
LL | #![deny(rustc::rustc_must_match_exhaustively)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: match is not exhaustive
|
||||
--> $DIR/must_match_exhaustively.rs:27:11
|
||||
|
|
||||
LL | #[rustc_must_match_exhaustively]
|
||||
| -------------------------------- required because of this attribute
|
||||
...
|
||||
LL | match f {
|
||||
| ^
|
||||
|
|
||||
= help: explicitly list all variants of the enum in a `match`
|
||||
note: because of this variable binding
|
||||
--> $DIR/must_match_exhaustively.rs:30:9
|
||||
|
|
||||
LL | a => {}
|
||||
| ^
|
||||
|
||||
error: match is not exhaustive
|
||||
--> $DIR/must_match_exhaustively.rs:33:11
|
||||
|
|
||||
LL | #[rustc_must_match_exhaustively]
|
||||
| -------------------------------- required because of this attribute
|
||||
...
|
||||
LL | match &f {
|
||||
| ^^
|
||||
|
|
||||
= help: explicitly list all variants of the enum in a `match`
|
||||
note: because of this variable binding
|
||||
--> $DIR/must_match_exhaustively.rs:36:9
|
||||
|
|
||||
LL | a => {}
|
||||
| ^
|
||||
|
||||
error: match is not exhaustive
|
||||
--> $DIR/must_match_exhaustively.rs:44:8
|
||||
|
|
||||
LL | #[rustc_must_match_exhaustively]
|
||||
| -------------------------------- required because of this attribute
|
||||
...
|
||||
LL | if let Foo::A { .. } = f {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: explicitly list all variants of the enum in a `match`
|
||||
note: using if let only matches on one variant (try using `match`)
|
||||
--> $DIR/must_match_exhaustively.rs:44:8
|
||||
|
|
||||
LL | if let Foo::A { .. } = f {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Reference in New Issue
Block a user