about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs36
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs19
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/patch.rs22
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs49
-rw-r--r--compiler/rustc_trait_selection/src/solve.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalize.rs57
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs13
8 files changed, 130 insertions, 70 deletions
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 807d62562db..4a171a08ef7 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -1,6 +1,12 @@
-// Type resolution: the phase that finds all the types in the AST with
-// unresolved type variables and replaces "ty_var" types with their
-// generic parameters.
+//! During type inference, partially inferred terms are
+//! represented using inference variables (ty::Infer). These don't appear in
+//! the final [`ty::TypeckResults`] since all of the types should have been
+//! inferred once typeck is done.
+//!
+//! When type inference is running however, having to update the typeck results
+//! every time a new type is inferred would be unreasonably slow, so instead all
+//! of the replacement happens at the end in [`FnCtxt::resolve_type_vars_in_body`],
+//! which creates a new `TypeckResults` which doesn't contain any inference variables.
 
 use std::mem;
 
@@ -26,15 +32,6 @@ use crate::FnCtxt;
 ///////////////////////////////////////////////////////////////////////////
 // Entry point
 
-// During type inference, partially inferred types are
-// represented using Type variables (ty::Infer). These don't appear in
-// the final TypeckResults since all of the types should have been
-// inferred once typeck is done.
-// When type inference is running however, having to update the typeck
-// typeck results every time a new type is inferred would be unreasonably slow,
-// so instead all of the replacement happens at the end in
-// resolve_type_vars_in_body, which creates a new TypeTables which
-// doesn't contain any inference types.
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(crate) fn resolve_type_vars_in_body(
         &self,
@@ -89,14 +86,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 }
 
-///////////////////////////////////////////////////////////////////////////
-// The Writeback context. This visitor walks the HIR, checking the
-// fn-specific typeck results to find references to types or regions. It
-// resolves those regions to remove inference variables and writes the
-// final result back into the master typeck results in the tcx. Here and
-// there, it applies a few ad-hoc checks that were not convenient to
-// do elsewhere.
-
+/// The Writeback context. This visitor walks the HIR, checking the
+/// fn-specific typeck results to find inference variables. It resolves
+/// those inference variables and writes the final result into the
+/// `TypeckResults`. It also applies a few ad-hoc checks that were not
+/// convenient to do elsewhere.
 struct WritebackCx<'cx, 'tcx> {
     fcx: &'cx FnCtxt<'cx, 'tcx>,
 
@@ -877,7 +871,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
             let cause = ObligationCause::misc(self.span.to_span(tcx), body_id);
             let at = self.fcx.at(&cause, self.fcx.param_env);
             let universes = vec![None; outer_exclusive_binder(value).as_usize()];
-            match solve::deeply_normalize_with_skipped_universes_and_ambiguous_goals(
+            match solve::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
                 at, value, universes,
             ) {
                 Ok((value, goals)) => {
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 4222a68e544..e5d1dda3aa0 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -115,15 +115,16 @@ impl<'tcx> TyCtxt<'tcx> {
                     // @lcnr believes that successfully evaluating even though there are
                     // used generic parameters is a bug of evaluation, so checking for it
                     // here does feel somewhat sensible.
-                    if !self.features().generic_const_exprs() && ct.args.has_non_region_param() {
-                        let def_kind = self.def_kind(instance.def_id());
-                        assert!(
-                            matches!(
-                                def_kind,
-                                DefKind::InlineConst | DefKind::AnonConst | DefKind::AssocConst
-                            ),
-                            "{cid:?} is {def_kind:?}",
-                        );
+                    if !self.features().generic_const_exprs()
+                        && ct.args.has_non_region_param()
+                        // We only FCW for anon consts as repeat expr counts with anon consts are the only place
+                        // that we have a back compat hack for. We don't need to check this is a const argument
+                        // as only anon consts as const args should get evaluated "for the type system".
+                        //
+                        // If we don't *only* FCW anon consts we can wind up incorrectly FCW'ing uses of assoc
+                        // consts in pattern positions. #140447
+                        && self.def_kind(instance.def_id()) == DefKind::AnonConst
+                    {
                         let mir_body = self.mir_for_ctfe(instance.def_id());
                         if mir_body.is_polymorphic {
                             let Some(local_def_id) = ct.def.as_local() else { return };
diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs
index 6f867f8105d..73a58160a6a 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drop.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs
@@ -376,7 +376,7 @@ where
         if self.tcx().features().async_drop()
             && self.elaborator.body().coroutine.is_some()
             && self.elaborator.allow_async_drops()
-            && !self.elaborator.body()[bb].is_cleanup
+            && !self.elaborator.patch_ref().block(self.elaborator.body(), bb).is_cleanup
             && drop_ty.needs_async_drop(self.tcx(), self.elaborator.typing_env())
         {
             self.build_async_drop(
diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs
index c7eb2a921c7..a872eae15f1 100644
--- a/compiler/rustc_mir_transform/src/patch.rs
+++ b/compiler/rustc_mir_transform/src/patch.rs
@@ -148,11 +148,20 @@ impl<'tcx> MirPatch<'tcx> {
         self.term_patch_map[bb].is_some()
     }
 
+    /// Universal getter for block data, either it is in 'old' blocks or in patched ones
+    pub(crate) fn block<'a>(
+        &'a self,
+        body: &'a Body<'tcx>,
+        bb: BasicBlock,
+    ) -> &'a BasicBlockData<'tcx> {
+        match bb.index().checked_sub(body.basic_blocks.len()) {
+            Some(new) => &self.new_blocks[new],
+            None => &body[bb],
+        }
+    }
+
     pub(crate) fn terminator_loc(&self, body: &Body<'tcx>, bb: BasicBlock) -> Location {
-        let offset = match bb.index().checked_sub(body.basic_blocks.len()) {
-            Some(index) => self.new_blocks[index].statements.len(),
-            None => body[bb].statements.len(),
-        };
+        let offset = self.block(body, bb).statements.len();
         Location { block: bb, statement_index: offset }
     }
 
@@ -284,10 +293,7 @@ impl<'tcx> MirPatch<'tcx> {
     }
 
     pub(crate) fn source_info_for_location(&self, body: &Body<'tcx>, loc: Location) -> SourceInfo {
-        let data = match loc.block.index().checked_sub(body.basic_blocks.len()) {
-            Some(new) => &self.new_blocks[new],
-            None => &body[loc.block],
-        };
+        let data = self.block(body, loc.block);
         Self::source_info_for_index(data, loc)
     }
 }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 1c542ebbebd..968376678f3 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -58,13 +58,62 @@ mod tokenstream {
 }
 
 bitflags::bitflags! {
+    /// Restrictions applied while parsing.
+    ///
+    /// The parser maintains a bitset of restrictions it will honor while
+    /// parsing. This is essentially used as a way of tracking state of what
+    /// is being parsed and to change behavior based on that.
     #[derive(Clone, Copy, Debug)]
     struct Restrictions: u8 {
+        /// Restricts expressions for use in statement position.
+        ///
+        /// When expressions are used in various places, like statements or
+        /// match arms, this is used to stop parsing once certain tokens are
+        /// reached.
+        ///
+        /// For example, `if true {} & 1` with `STMT_EXPR` in effect is parsed
+        /// as two separate expression statements (`if` and a reference to 1).
+        /// Otherwise it is parsed as a bitwise AND where `if` is on the left
+        /// and 1 is on the right.
         const STMT_EXPR         = 1 << 0;
+        /// Do not allow struct literals.
+        ///
+        /// There are several places in the grammar where we don't want to
+        /// allow struct literals because they can require lookahead, or
+        /// otherwise could be ambiguous or cause confusion. For example,
+        /// `if Foo {} {}` isn't clear if it is `Foo{}` struct literal, or
+        /// just `Foo` is the condition, followed by a consequent block,
+        /// followed by an empty block.
+        ///
+        /// See [RFC 92](https://rust-lang.github.io/rfcs/0092-struct-grammar.html).
         const NO_STRUCT_LITERAL = 1 << 1;
+        /// Used to provide better error messages for const generic arguments.
+        ///
+        /// An un-braced const generic argument is limited to a very small
+        /// subset of expressions. This is used to detect the situation where
+        /// an expression outside of that subset is used, and to suggest to
+        /// wrap the expression in braces.
         const CONST_EXPR        = 1 << 2;
+        /// Allows `let` expressions.
+        ///
+        /// `let pattern = scrutinee` is parsed as an expression, but it is
+        /// only allowed in let chains (`if` and `while` conditions).
+        /// Otherwise it is not an expression (note that `let` in statement
+        /// positions is treated as a `StmtKind::Let` statement, which has a
+        /// slightly different grammar).
         const ALLOW_LET         = 1 << 3;
+        /// Used to detect a missing `=>` in a match guard.
+        ///
+        /// This is used for error handling in a match guard to give a better
+        /// error message if the `=>` is missing. It is set when parsing the
+        /// guard expression.
         const IN_IF_GUARD       = 1 << 4;
+        /// Used to detect the incorrect use of expressions in patterns.
+        ///
+        /// This is used for error handling while parsing a pattern. During
+        /// error recovery, this will be set to try to parse the pattern as an
+        /// expression, but halts parsing the expression when reaching certain
+        /// tokens like `=`.
         const IS_PAT            = 1 << 5;
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs
index 0c2451a80a7..5a5d16167d2 100644
--- a/compiler/rustc_trait_selection/src/solve.rs
+++ b/compiler/rustc_trait_selection/src/solve.rs
@@ -11,6 +11,6 @@ pub use fulfill::{FulfillmentCtxt, NextSolverError};
 pub(crate) use normalize::deeply_normalize_for_diagnostics;
 pub use normalize::{
     deeply_normalize, deeply_normalize_with_skipped_universes,
-    deeply_normalize_with_skipped_universes_and_ambiguous_goals,
+    deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals,
 };
 pub use select::InferCtxtSelectExt;
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index 5f1e63ab225..d903f94b489 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -45,9 +45,11 @@ where
     T: TypeFoldable<TyCtxt<'tcx>>,
     E: FromSolverError<'tcx, NextSolverError<'tcx>>,
 {
-    let (value, goals) =
-        deeply_normalize_with_skipped_universes_and_ambiguous_goals(at, value, universes)?;
-    assert_eq!(goals, vec![]);
+    let (value, coroutine_goals) =
+        deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
+            at, value, universes,
+        )?;
+    assert_eq!(coroutine_goals, vec![]);
 
     Ok(value)
 }
@@ -59,9 +61,9 @@ where
 /// entered before passing `value` to the function. This is currently needed for
 /// `normalize_erasing_regions`, which skips binders as it walks through a type.
 ///
-/// This returns a set of stalled obligations if the typing mode of the underlying infcx
-/// has any stalled coroutine def ids.
-pub fn deeply_normalize_with_skipped_universes_and_ambiguous_goals<'tcx, T, E>(
+/// This returns a set of stalled obligations involving coroutines if the typing mode of
+/// the underlying infcx has any stalled coroutine def ids.
+pub fn deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals<'tcx, T, E>(
     at: At<'_, 'tcx>,
     value: T,
     universes: Vec<Option<UniverseIndex>>,
@@ -71,11 +73,16 @@ where
     E: FromSolverError<'tcx, NextSolverError<'tcx>>,
 {
     let fulfill_cx = FulfillmentCtxt::new(at.infcx);
-    let mut folder =
-        NormalizationFolder { at, fulfill_cx, depth: 0, universes, stalled_goals: vec![] };
+    let mut folder = NormalizationFolder {
+        at,
+        fulfill_cx,
+        depth: 0,
+        universes,
+        stalled_coroutine_goals: vec![],
+    };
     let value = value.try_fold_with(&mut folder)?;
     let errors = folder.fulfill_cx.select_all_or_error(at.infcx);
-    if errors.is_empty() { Ok((value, folder.stalled_goals)) } else { Err(errors) }
+    if errors.is_empty() { Ok((value, folder.stalled_coroutine_goals)) } else { Err(errors) }
 }
 
 struct NormalizationFolder<'me, 'tcx, E> {
@@ -83,7 +90,7 @@ struct NormalizationFolder<'me, 'tcx, E> {
     fulfill_cx: FulfillmentCtxt<'tcx, E>,
     depth: usize,
     universes: Vec<Option<UniverseIndex>>,
-    stalled_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
+    stalled_coroutine_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
 }
 
 impl<'tcx, E> NormalizationFolder<'_, 'tcx, E>
@@ -182,7 +189,7 @@ where
             return Err(errors);
         }
 
-        self.stalled_goals.extend(
+        self.stalled_coroutine_goals.extend(
             self.fulfill_cx
                 .drain_stalled_obligations_for_coroutines(self.at.infcx)
                 .into_iter()
@@ -298,13 +305,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_,
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         let infcx = self.at.infcx;
-        let result =
-            infcx.commit_if_ok(|_| {
-                deeply_normalize_with_skipped_universes_and_ambiguous_goals::<
-                    _,
-                    ScrubbedTraitError<'tcx>,
-                >(self.at, ty, vec![None; ty.outer_exclusive_binder().as_usize()])
-            });
+        let result: Result<_, Vec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| {
+            deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
+                self.at,
+                ty,
+                vec![None; ty.outer_exclusive_binder().as_usize()],
+            )
+        });
         match result {
             Ok((ty, _)) => ty,
             Err(_) => ty.super_fold_with(self),
@@ -313,13 +320,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_,
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         let infcx = self.at.infcx;
-        let result =
-            infcx.commit_if_ok(|_| {
-                deeply_normalize_with_skipped_universes_and_ambiguous_goals::<
-                    _,
-                    ScrubbedTraitError<'tcx>,
-                >(self.at, ct, vec![None; ct.outer_exclusive_binder().as_usize()])
-            });
+        let result: Result<_, Vec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| {
+            deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
+                self.at,
+                ct,
+                vec![None; ct.outer_exclusive_binder().as_usize()],
+            )
+        });
         match result {
             Ok((ct, _)) => ct,
             Err(_) => ct.super_fold_with(self),
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index d38ddbc825c..5f0acd46f86 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -260,11 +260,14 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
             }
 
             ty::Projection if !data.has_escaping_bound_vars() => {
-                // This branch is *mostly* just an optimization: when we don't
-                // have escaping bound vars, we don't need to replace them with
-                // placeholders (see branch below). *Also*, we know that we can
-                // register an obligation to *later* project, since we know
-                // there won't be bound vars there.
+                // When we don't have escaping bound vars we can normalize ambig aliases
+                // to inference variables (done in `normalize_projection_ty`). This would
+                // be wrong if there were escaping bound vars as even if we instantiated
+                // the bound vars with placeholders, we wouldn't be able to map them back
+                // after normalization succeeded.
+                //
+                // Also, as an optimization: when we don't have escaping bound vars, we don't
+                // need to replace them with placeholders (see branch below).
                 let data = data.fold_with(self);
                 let normalized_ty = project::normalize_projection_ty(
                     self.selcx,